SpringMVC 作用
解决了View -> Controller和Controller -> View的细节问题,简化了开发。
开发Spring MVC的项目
1 创建项目,加载Spring
创建Maven Project,通过Eclipse生成web.xml,添加Tomcat运行环境,添加spring-webmvc依赖,复制配置文件spring-mvc.xml。
在web.xml中配置DispatcherServlet接收*.do请求,并为这个Servlet添加初始化参数,参数名称是contextConfigLocation,值为classpath:spring-mvc.xml,即取值是Spring的配置文件,然后将这个Servlet配置为默认加载。
经过以上配置后,当Tomcat启动该项目时,就会加载DispatcherServlet,并在过程中加载spring-mvc.xml的配置文件。
2 接收请求
首先,设计好请求的路径,例如http://SERVER:PORT/PROJECT/hello.do。
经过第1步骤的配置,当客户端提交以上路径的请求时,DispatcherServlet将开始运行,首先,会去找HandlerMapping,查询该请求路径对应哪个Controller,所以,此时应该配置HandlerMapping,在SpringMVC中,实际工作的会是SimpleUrlHandlerMapping,所以,需要在spring-mvc.xml对这个类进行配置,配置时不需要指定bean id,因为后续在工作时,SpringMVC会根据类型完全装配。
在配置SimpleUrlHandlerMapping时,这个类中的mappings属性是用于确定请求路径与Controller的映射关系的,所以,需要配置该属性。这个属性是Properties类型的,所以将通过和若干个节点进行配置:
Controller bean id 至此,就必须开始开发Controller,在SpringMVC中,Controller是接口,需要自定义类实现该接口,并重写其中的抽象方法:public class HelloController implements Controller {
// 重写抽象方法
}
由于此前的SimpleUrlHandlerMapping的配置中需要使用HelloController的bean id,所以,需要在HelloController类上添加注解,可以使用@Component,也可以使用@Controller:
@Controller
public class HelloController implements Controller {
// 重写抽象方法
}
注意:必须开启组件扫描,且能够扫描到相关的类所在的包!
3 准备响应
实现Controller接口后,需要重写的抽象方法是:
public ModeAndView handleRequest(
HttpServletRequest request, HttpServletResponse response)
throws Exception {
}
这个方法的使用和Servlet中的service()或doGet()或doPost()类似,区别在于这个方法必须返回ModelAndView类型的对象!
ModelAndView应该是一个封装了需要转发的数据和转发的目标(View,通常是jsp页面)的对象,且强烈推荐需要确定转发的目标,此时,应该先设计好由哪个jsp页面进行视图的显示,假设是项目中的/WEB-INF/hello.jsp,则在ModelAndView对象中设置的viewName就是这个jsp的文件名部分,即hello。
当Controller返回了ModelAndView对象后,DispatcherServlet将可以明确接下来由哪个名为viewName(即hello)负责最后的显示,但是,并不明确这个viewName对应的是哪个视图组件(哪个jsp页面),此时,DispatcherServlet将通过ViewResolver来确定,所以,需要在spring-mvc.xml中进行配置。
与HandlerMapping相似,ViewResolver也是一个接口,实际使用的类可能有多种,目前推荐使用InternalResourceViewResolver,后续在运行过程中,SpringMVC依然是通过类型来装配使用这个ViewResolver,所以,还是需要在spring-mvc.xml中配置,且还是不需要配置bean id,需要配置的属性有prefix和suffix,分别表示前缀与后缀,最终,前缀与后缀与此前ModelAndView中的viewName组合起来,就是jsp文件的路径,所以,配置如下:
最后,创建对应的jsp,也就是/WEB-INF/hello.jsp,设计界面的内容,如果此前ModelAndView中还封装了数据,则在这个jsp页面中还可以通过EL表达式去显示这些数据!Spring MVC - HelloWorld - 新款 - 开发步骤
1 创建项目,加载Spring
参考旧款
2 接收并处理请求
设计请求路径:http://SERVER:PORT/PROJECT/hello.do
先跳过HandlerMapping的步骤,直接创建Controller类:
public class HelloController { …
创建类之后,先在类之前添加注解@Controller:
@Controller
public class HelloController { …
注意:新款做法中不必再实现Controller接口!
在类中添加处理请求的方法:
public ModelAndView handleRequest(
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return null;
}
在方法内部,自行编写如何处理请求,无论如何,最终返回的必须是ModelAndView对象,并且指定了View组件名。
至此,已经完成了使用Controller接收并处理请求,却还没有配置请求路径与Controller的映射关系,新的做法是在处理请求的方法上添加注解:
@RequestMapping("/hello.do")
public ModelAndView handleRequest(
当完成以上注解后,在SpringMVC工作时,就已经有了“请求路径与处理方法”之间的映射关系!
事实上,处理请求的方法名称可以*定义,方法的参数可以*定义,例如:
@RequestMapping("/hello.do")
public ModelAndView showHello() {
// …
}
并且,返回值类型不一定是ModelAndView类型的,如果响应的方式只是单纯的转发请求,并且没有数据需要转发到jsp页面,可以将返回值设计为String类型。
3 准备响应
参考旧款,配置ViewResolver,创建jsp页面即可。
小结
在编写Controller类时,不必实现接口,方法均可以*定义,注意:
1 方法的权限应该是public的,方法使用@RequestMapping进行注解
2 方法的返回值可以是String,也可以是ModelAndView,或其它类型,暂时只在String和ModelAndView中二选一,无论是哪种,必须体现后续将由哪个View负责响应
3 不必再配置HandlerMapping,但是,还是需要配置ViewSolver
练习
设计请求:http://SERVER:PORT/PROJECT/login.do
响应请求的类:cn.tedu.spring.UserController
响应请求的方法:public String showLogin()
响应页面:/WEB-INF/login.jsp
页面内容:添加2个输入框,分别表示用户名和密码,输入框的name属性分别是username和password
在Spring MVC中接收用户的请求参数
1 设计
请求路径:http://SERVER:PORT/PROJECT/handleLogin.do
请求方式:POST
请求参数:username=tomcat&password=1234
2 开发步骤
在UserController添加方法:
public String handleLogin() {
return null;
}
使用@RequestMapping注释该方法:
@RequestMapping("/handleLogin.do")
public String handleLogin() {
return null;
}
在处理请求的方法中,添加与前端页面提交的数据的名称相匹配的参数:
@RequestMapping("/handleLogin.do")
public String handleLogin(String username, String password) {
return null;
}
在SpringMVC调用handleLogin()方法时,就会自动将提交的参数用于调用方法,所以,在编写方法时,直接使用这些参数即可!
在Spring MVC中响应用户的请求
1 设计
基于以上的案例,假设正确的用户名是tomcat,匹配的密码是123456,则可以判断用户登录成功与否。
在Controller中判断登录后,将登录结果保存在String result变量中,转发到jsp。
使用login_result.jsp页面显示登录结果,在该页面中提示“登录成功”或“用户名不存在,登录失败”或“密码错误,登录失败”的字样。
2 开发步骤
首先,在WEB-INF下创建login_result.jsp,通过EL表达式${result }显示登录结果。
在Controller中的handleLogin()方法中,判断用户名和密码,为String result变量进行赋值。
将result转发。
返回"login_result"。
注解
@RequestParam
该注解用于对Controller中的方法的参数进行注解。
如果前端页面提交的数据的参数名与Controller中方法的参数名不一致,则可以使用该注解:
@RequestMapping("/handleLogin.do")
public String handleLogin(
@RequestParam(“uname”) String username,
@RequestParam(“upwd”) String password) {
// …
}
@RequestMapping
在一般情况下,使用@RequestMapping(“xxx”)用于标识接下来方法将处理哪个请求路径。
也可以在注解中添加更多的参数:
@RequestMapping(
method=RequestMethod.POST,
value="/handleLogin.do")
@RequestMapping不仅仅是用于对方法进行注解,还可以对类进行注解:
@RequestMapping("/user")
@Controller
public class UserController { …
在类上面的@RequestMapping并不能取代方法上面的注解,只是用于添加请求的路径而已,当添加以上注解后,这个Controller中将处理的请求都必须是http://SERVER:PORT/PROJECT/user这个路径之下的某个资源!
注意:无论使用@RequestMapping注解类还是方法,其参数都推荐使用/开头!!!
今天重点
获取请求参数
1 【不推荐】 在处理请求的方法中添加HttpServletRequest参数,然后调用getParameter()方法
2 【推荐】 在处理请求的方法中添加与请求参数名称匹配的参数,这些参数的值就是请求参数的值,如果请求参数中的名称与处理请求的方法中的参数名称不一致,还可以使用@RequestParam注解来解决,这种做法的不足在于不适用于过多请求参数
3 【推荐】 如果前端页面提交的请求参数较多,则应该在服务器端创建对应的实体类,然后,在处理请求的方法中添加实体类作为参数即可,SpringMVC会自动将请求参数用于对实体类对象的属性进行赋值!使用这种做法时,需要保证请求参数的名称与实体类中的属性名称和数据类型保持一致!
向jsp转发数据
1 【不推荐】 为方法添加HttpServletRequest,然后向该对象中封装需要转发的数据
2 【一般】 需要将处理请求的方法的返回值设置为ModelAndView类型,将转发的数据先封装到Map<String, ?>,然后通过ModelAndView的构造方法使用该Map<String, ?>,最后返回ModelAndView对象
public ModelAndView handleLogin(String username, String password) {
String result;
if ("tomcat".equals(username)) {
if ("123456".equals(password)) {
result = "登录成功!";
} else {
result = "密码错误,登录失败!";
}
} else {
result = "用户名不存在,登录失败!";
}
// 将result封装,以准备转发到jsp
String viewName = "login_result";
Map<String, Object> model
= new HashMap<String, Object>();
model.put("result", result);
ModelAndView mav
= new ModelAndView(viewName, model);
// 返回,执行转发
return mav;
}
3 【推荐】 在处理请求的方法中添加新的参数ModelMap,方法的返回值类型不需要是ModelAndView,可以根据需求选择返回值类型,例如设置为String类型的返回值,然后,在方法中,调用ModelMap对象的addAttribute(String, Object)方法即可封装数据,后续该ModelMap中的数据将被转发,而不需要编写其它代码。
public String handleLogin(
String username,
String password,
ModelMap modelMap) {
// 声明登录结果
String result;
// 判断...
// 将需要转发的数据封装到ModelMap中
modelMap.addAttribute(
"result", result);
// 执行转发
return "login_result";
}
处理HttpSession
不推荐的做法是在处理请求的方法中添加HttpServletRequest,然后调用它的getSession()获取HttpSession对象。
推荐的做法可参考HttpServletRequest或ModelMap,也就是在处理请求的方法中添加HttpSession参数:
public String handleLogin(String username, String password,
HttpSession session) {
// 通过session参数封装数据到HttpSession,或获取其中的数据
}
转发与重定向
在Controller中,处理请求的方法最终需要转发或重定向时,都推荐使用String类型的返回值:
public String xxx { …
默认的方式是转发,所以,当需要转发时,直接返回View组件的名称就可以,也可以添加forward:前缀:
public String xxx {
return “index”;
}
public String xxx {
return “forward:index”;
}
重定向的作法是使用redirect:作为前缀:
public String xxx {
return “redirect:index”;
}
另外:还可以在方法中创建RedirectView对象,然后装其封装到ModelAndView中,以实现重定向,但是,不推荐。