SpringMVC传统风格控制器和基于注解的控制器
SpringMVC的DispatcherServlet
之前说过springMVC是使用Servlet作为控制器,就是这个用于调度的DispatcherServlet了。这个是servlet,可以根据URI调用相应的action,接受请求做出相应。要使用这个servlet,需要在部署描述符(web.xml文件)中使用servlet和servlet-mapping元素来配置:
<!--配置前端控制器 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定springmvc配置文件位置 -->
<!-- <init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param> -->
<!--使用默认配置:位置/WEB-INF/<servlet-name>-servlet.xml -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
load-on-start元素是可选的,如果它存在,则它将在应用程序启动的时候装载servlet并调用它的init方法。若不存在,则在该servlet 的第一个请求时加载。 url-pattern 值为/ ,表明所有请求都交给这个调度servlet来处理。
DispatcherServlet将使用SpringMVC诸多的默认组件,在默认情况下,它会寻找在应用程序的WEB-INF目录下的一个配置文件,该配置文件命名是有要求的:
servletName-servlet.xml
其中,servletName是部署描述符中的DispatcherServlet的名称。
其实可以把这个配置文件放在应用程序目录中的任何地方,只需要告诉DispatcherServlet在哪里可以找到这个配置文件即可.我们使用servlet声明下的一个init-param元素可以做到这一点。init-param拥有一个名为contextConfigLocation的param-name元素,其param-value元素则包含配置文件的路径。
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
旧版springMVC程序开发
在spring2.5前,开发一个控制器唯一的方法是实现org.springframework.web.servlet.mvc.Controller接口。这个接口公开了一个handlerRequest方法。方法签名如下:
ModelAndView handlerRequest(HttpServletRequest request,HttpServletResponse response)
实现类可以访问对应请求和响应,还必须返回一个ModelAndView对象,它包含视图路径和模型数据。
值得说的是:springMVC依赖于Apache Commons Logging组件,没有这个jar,springMVC就无法正常工作。
还需要在springMVC的配置文件中配置请求和所对应的控制器:
Spring MVC配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--name:请求URI value:对应的控制器-->
<bean name="/save" class="cn,lynu.controller.SaveController"></bean> </beans>
实现Controller接口只能处理一个单一动作(action),也就是在handlerRequest方法中处理动作。而实现注解的控制器可以支持多个请求动作,而且无需实现任何接口。
基于注解的控制器
使用基于注解的控制器的优点:
其一:一个控制器类可以处理多个动作(而实现了Controller接口的实现类只能处理一个动作)。这就允许将相关的操作写在同一个类中,从而减少应用中类的数量。
其二:基于注解的控制器的请求不需要配置在配置文件中。使用@RequestMapping可以对一个方法进行请求映射。
Spring使用扫描机制来找到程序中所有的基于注解的控制器,为了spring可以找到你的控制器,需要完成两件事:
- 在配置文件中声明使用context,也就是引入spring-context约束。
- 使用组件扫描标签:<context-component-scan>
<!-- 配置扫描的包-->
<context:component-scan base-package="cn.lynu.controller"></context:component-scan>
@RequestMapping注解
@RequestMapping注解的作用同其名字一样:映射一个请求和一个方法。可以使用@RequestMapping注解一种方法或类。使用该注解的value属性将URI映射到方法上,由于value属性是默认属性,所以只有唯一的属性,则可以省略属性名称,但是有多个属性时,就必须写入value属性名称。请求映射到值可以是一个空字符串,此时该方法被映射到以下地址:
http://domain/context
RequestMapping除了具有value属性外,还有其他属性,如:method属性用来指示方法仅处理哪些HTTP方法。
如果使用该注解注解一个类,在这种情况下,该类的所有方法都将映射为相对于类级别的请求,也就是访问需要加上类的请求地址。
请求处理方法
每个请求处理方法都可以有任意多个不同类型的参数,以及一个多种类型的返回结果。
部分可以出现在请求处理方法的形参:
- javax.servlet.ServletRequest 或 javax.servlet.http.HttpServletRequest
- javax.servlet.ServletRresponse或 javax.servlet.http.HttpServletResponse
- javax.servlet.http.HttpSession
- java.io.InputStram 或 java.io.Reader
- java.io.OutputStream 或 java.io.Writer
- java.util.Map/org.springframework.ui.Model
- org.springframework.ui.ModelMap
- org.springframework.web.servlet.ModelAndView
- POJO/表单对象
- @PathVariable,@RequestParam,@RequestHeader,@RequestBody,@CookieValue注释的对象
...
部分可以做为处理方法返回类型的对象:
- ModelAndView
- void
- Model
- 包含模型数据的Map
- 包含逻辑视图名的String
- ModelMap
- Callable
...
配置处理静态资源和功能
因为我们将DispatcherServlet的servletMapping设置为“/”,所有的请求都会交给spring处理,所以为了可以正确处理静态资源,需要在springMVC的配置文件配置<mvc:default-servlet-handler/>,表明静态资源需要单独处理(不通过DispatcherServlet)
我们在配置一个<mvc:annotation-driven/>,用于支持一些功能,如JSR303校验,注册用于控制器注解的bean对象等等,这个标签较为有用。
这两个标签较为常用,所以一般都需要配置:
<!--两个标准配置 -->
<!-- 将springmvc不能处理的请求交给tomcat -->
<mvc:default-servlet-handler/>
<!-- 能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax...映射动态请求 -->
<mvc:annotation-driven/>
使用注解进行依赖注入
之前我们说过了最基本的构造注入和setter注入,使用注解也是可以的,我之前在使用SSH整合的时候在Controller中使用 @Resource和service层使用@Service ,其实也可以使用@Autowired 和service层使用@Service。其实 @Resource和@Autowired作用是一样的,@Resource还需要指定name值,所以我们使用@Autowired即可。
重定向传值
我们都知道请求域中的数据再转发之后还可以获得,但是重定向之后就不行了,原理这里就不分析了。在springMVC 3.1版本之后可以添加一个新的参数类型org.springframework.web.servlet.mvc.support.RedirectAttributes。这称之为通过Flash属性提供一种重定向传值的方法。
@RequestMapping("/testRedirect")
public String testRedirect(RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("userName", "lz");
return "redirect:/WEB-INF/view/success.jsp";
}
重定向目标方如果是Controller,则使用Map/Model/ModelMap根据key取值即可,无法使用RedirectAttributes对象取到这个值;如果目标方是JSP,使用EL(${sessionScope.org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS[0].userName})直接将数据取出来即可。
请求参数和路径变量
请求参数和路径变量都可以用于发送值给服务器,二者都是URL的一部分。
请求参数使用key=value形式,并用“&” 分割。在传统servlet编程中,可以使用HttpServletRequest的getParameter方法获得一个请求参数值。springMVC提供了一个更为简单的方法,使用org.springframework.web.bind.annotation.RequestParam注解类型来注解方法参数。
/**
* 测试@RequestParam
*/
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam("userName")String userName,
@RequestParam(value="age",required=false,defaultValue="0")Integer age) {
System.out.println("userName:"+userName+" age:"+age);
return SUCCESS;
}
required=false表明这个属性不是必须的,默认情况下,required=true如果没有传入该值,会报异常。defaultValue说明如果该参数不存在的情况下的默认值。
请求URL:
<a href="h/testRequestParam?userName=lz&age=21">使用RequestParam注解</a><br><br>
路径变量类似于请求参数,但没有key部分,只有一个值。如以下的URL:
<a href="h/rest/1">REST get</a><br><br>
为了使用路径变量,首先需要在RequestMapping注解的值属性中添加一个变量,该变量必须放在花括号之间。@PathVariable注解来获得路径变量。
@RequestMapping(value="/rest/{id}",method=RequestMethod.PUT)
public String testRESTPut(@PathVariable("id")Integer id) {
System.out.println("id是:"+id);
return SUCCESS;
}
可以看到路径参数的对应形参类型可以不是String类型,springMVC会尽力转成我们所需的类型。
而且路径参数可以有多个:/rest/{id}/{userName}
但是路径参数可能会带来一个问题就是:在某些特殊情况下,如一个应用程序被部署为默认上下文(默认上下文路径就是一个空字符串),这种情况下,页面中的CSS/JS等路径如果使用相对路径就会找不到
,这时我们使用JSTL的<c:url value=“”>来解析URL可修复该问题:
<style type="text/css" href="<c:url value='/css/main.css'/>"></style>
@ModelAttribute
SpringMVC每次调用请求处理方法的时候,都会创建一个Model类型的实例,如果需要使用Model对象,只需在方法形参添加一个Model类型的参数即可。我们还可以通过@ModelAttribute注解来访问Model实例,这个注解是org.springframeword.eb.bind.annotation包的成员.
可以使用@ModelAttribute注解来修饰方法或方法的形参。
@ModelAttribute注解来修饰形参
@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("user")User user,Model model) {
System.out.println(user);
return SUCCESS;
}
表示将user对象放入到Model中,key为user,值为user对象,实际上可以不指定key,这时将使用参数类型首字母小写的key名。
@ModelAttribute注解来修饰非请求方法
修饰方法,但是这个方法只能是一个非请求的处理方法。被@ModelAttribute注解的方法会在每次调用该控制器类的请求处理方法之前被调用,这意味着,被@ModelAttribute注解的方法会多次被调用,不论是否需要。
被@ModelAttribute注解的方法可以返回一个对象或void类型。
1.如果返回一个对象,则这个会自动添加到Model中。
@ModelAttribute
public User getUser() {
//模拟从数据库中获得数据
return new User(1, "lz", 21);
}
2.如果返回void,则需要添加一个Model类型的参数,需要自行将实例添加到Model中。
@ModelAttribute
public void getUser(Model model) {
model.addAttribute(new User(1, "lz", 21));
}
推荐使用返回为void自行添加入Model的方式,因为这样我们可以进行判断空值就不放入Model:
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id,Model model) {
if(id==null) {
return;
}
model.addAttribute(new User(1,'"lz",21));
}
因为被@ModelAttribute注解的方法会多次被调用,有这样的需求可能会用到:
表单提交过来的值,我们不想让其修改某一项(如password),如果只是根据表单传过来的值封装为一个POJO,那么这个POJO的password项是为null的,因为我们不想让用户修改,所以这项就不会显示出来,但是用户填完表单之后需要修改保存进数据库,如果password为null,就将密码搞掉了,这并不是我们想要的,这是可以使用@ModelAttribute注解来修饰非请求方法,我们在表单添加一个隐藏域,隐藏域值就是id吧,@ModelAttribute注解修饰的非请求方法会在请求方法之前调用,所以我们可以拿着这个id从数据库中查出该用户,然后将其存入Model,请求处理方法在从Model中拿到该对象根据表单提交过来的值覆盖对应的值即可,这样就不将password值置为空了。
/**
* 测试ModelAttribute
*/
@ModelAttribute
public User getUser(@RequestParam(value="id",required=false)Integer id) {
if(id==null){
return;
}
//模拟从数据库中获得数据
return new User(1, "lz", 21);
}
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println(user);
return SUCCESS;
}
一定要加上required=false,因为其他请求方法之前也会调用该方法,所以不设置为false会报异常,其他的请求处理方法就用不成了。
在页面上使用一个表单来供用户修改除了password的值:
<form action="h/testModelAttribute" method="post">
<input name="id" type="hidden" value="1"/>
姓名:<input type="text" name="userName" value="lz"/></br>
<input type="submit" value="Submit"/>
</form><br><br>
这样修改保存在数据库中的password值也不会置空了。
SpringMVC传统风格控制器和基于注解的控制器的更多相关文章
- springMVC基于注解的控制器
springMVC基于注解的控制器 springMVC基于注解的控制器的优点有两个: 1.控制器可以处理多个动作,这就允许将相关操作写在一个类中. 2.控制器的请求映射不需要存储在配置文件中.使用re ...
- SpringMVC + ehcache( ehcache-spring-annotations)基于注解的服务器端数据缓存
背景 声明,如果你不关心java缓存解决方案的全貌,只是急着解决问题,请略过背景部分. 在互联网应用中,由于并发量比传统的企业级应用会高出很多,所以处理大并发的问题就显得尤为重要.在硬件资源一定的情况 ...
- SpringMVC学习(三)——基于注解配置的springMVC项目
可运行的附件地址:http://files.cnblogs.com/files/douJiangYouTiao888/springWithAnnotation.zip 项目说明: 作者环境:maven ...
- Spring MVC---基于注解的控制器
基于注解的控制器 SpringMVC是一个基于DispatcherServlet的MVC框架,每个请求最先访问的是Dispatcher ...
- SpringMVC之基于注解的Controller
参考博客:https://www.cnblogs.com/qq78292959/p/3760560.html Controller注解: 传统风格的Controller需要实现Controller接口 ...
- 【Spring】基于注解的实现SpringMVC+MySQL
目录结构: // contents structure [-] SprinigMVC是什么 SpringMVC工作原理 @Controller和@RequestMapping注解 @Controlle ...
- 【Spring】SpringMVC之基于注解的实现SpringMVC+MySQL
目录结构: contents structure [-] SprinigMVC是什么 SpringMVC工作原理 @Controller和@RequestMapping注解 @Controller注解 ...
- MVC模式到传统风格的Spring MVC
现在我们要做个简单的基于servlet的MVC的模型,我们要有一个Product要从表单处获取. MVC中的M是模型,V是视图,C是控制器.视图负责应用的展示,模型封装了数据和业务逻辑,控制器负责接收 ...
- 03springMVC注解式控制器开发
注解式控制器开发简介 注解式控制器开发HelloWorld HelloWorld的运行流程 处理器定义 REST简介 URL路径映射 数据绑定 不同的Model有相同的属性的处理 静态资源的处理 1 ...
随机推荐
- c# DataTable行转列
/// <summary> /// datatable行转列 /// </summary> /// <param name="dtSrc">来源 ...
- flask 文件的上传下载和excel操作
文件的下载 from flask import send_from_directory @excel_bp.route('/get_attachment/<path:filename>') ...
- 深度学习(七十)darknet 实现编写mobilenet源码
一.添加一个新的网络层 (1)parse.c文件中函数string_to_layer_type,添加网络层类型解析: if (strcmp(type, "[depthwise_convolu ...
- learn go defer
package main // 参考文档: // https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/06.4.md im ...
- 正确的使用margin:0 auto与body{text-align:center;}实现元素居中(转)
body{text-align:center}与margin:0 auto的异同? text-align是用于设置或对象中文本的对齐方式.一般情况下我们设置文本对齐方式的时候需要用此属性进行设置 我们 ...
- javascript的slice()与splice()方法
(1)数组和String对象都有slice()方法. //Array var list = ['A','B','C','D','DS']; console.log(list.slice(,));//截 ...
- IDEA中项目统一编码格式设置
统一UTF-8编码设置 第一处 File-settings-Editor-File Encodings 第二处 File-Other settings-Default settings 第三处 tom ...
- 【Codeforces】Round #488 (Div. 2) 总结
[Codeforces]Round #488 (Div. 2) 总结 比较僵硬的一场,还是手速不够,但是作为正式成为竞赛生的第一场比赛还是比较圆满的,起码没有FST,A掉ABCD,总排82,怒涨rat ...
- hexo个人博客搭建
遇见西门的个人博客 https://www.simon96.online/ 内容详细!
- 在 Windows 安装期间将 MBR 磁盘转换为 GPT 磁盘
以 UEFI 启动的 Windows 磁盘必须是 GPT 格式.本文将介绍如何在安装 Windows 期间将磁盘从 MBR 转换成 GPT. 特别注意:操作不慎可能丢失所有数据,如果你懂得安装系统的一 ...