一、配置
1、pmo.xml文件中加入spring所需依赖
<!--spring所需依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!--其他需要的包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
2、添加框架支持
右击我们的项目文件夹,选择add framework support
然后在窗口中分别选中spring和springmvc,并且选择spring是,记得勾选springconfig.xml
如果没有看见spring相关选项,说明系统已经默认,可以到Project StruStructure—Mudules–删掉Spring项…然后回头再来选一次即可看见
3、完善目录结构
创建相关文件夹
4、xml文件配置
1、配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<!--开始页面-->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--配置Spring IoC配置文件路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!--配置ContextLoaderListener用以初始化Spring IoC容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置DispatcherServlet-->
<servlet>
<!--Spring MVC会根据servlet-name配置,找到/WEB-INF/dispatcher-servlet.xml作为配置文件载入Web工程中-->
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--配置dispatcher.xml作为mvc的配置文件-->
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<!--使得Dispatcher在服务器启动的时候就初始化-->
<load-on-startup>2</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<!--servlet拦截配置-->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
2、配置applicationContext.xml文件
<?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:tx="http://www.springframework.org/schema/c"
xsi:schemaLocation="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">
</beans>
3、配置Spring MVC配置文件dispatcher-servlet.xml
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--启用spring的一些annotation -->
<context:annotation-config/>
<!--使用注解驱动-->
<mvc:annotation-driven />
<!--自动扫描装配-->
<context:component-scan base-package="example.controller" />
<!--静态资源映射-->
<!--本项目把静态资源放在了webapp的statics目录下,资源映射如下-->
<mvc:resources mapping="/css/**" location="/WEB-INF/statics/css/"/>
<mvc:resources mapping="/js/**" location="/WEB-INF/statics/js/"/>
<mvc:resources mapping="/image/**" location="/WEB-INF/statics/image/"/>
<!--定义视图解析器-->
<!--找到Web工程/WEB-INF/view文件夹,且文件结尾为jsp的文件作为映射-->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/view/" p:suffix=".jsp" />
<!--如果有配置数据库事务,需要开启注解事务的,需要开启这段代码-->
<!--
<tx:annotation-driven transaction-manager="transactionManager" />
-->
</beans>
二、简单使用
Controller实例:
@Controller("myController")
@RequestMapping("/role")
public class RoleController{
@Autowired
private RoleService roleService = null;
@RequestMapping(value = "/getRole", method = RequestMethod.GET)
public ModelAndView getRole(@RequestParam(value = "id", required = false) Long id){
Role role = roleService.getRole(id);
ModelAndView mv = new ModelAndView();
mv.setViewName("roleDetails");
mv.addObject("role", role);
return mv;
}
}
@Controller代表该类是一个控制器类,Spring MVC 扫描的时候就会把它作为控制器加载进来。
@RequestMapping指定了对应的请求的URI以及请求类型(如果没有配置请求类型,那么所有的请求都会响应),Spring MVC在初始化的时候就会将这些信息解析,存放起来,于是就有了HandlerMapping。
@RequestParam(value = “id”, required = false) Long id代表获取一个HTTP请求的长整型参数——id,默认情况下要求该参数不能为空,可以设置配置项required=false,代表允许参数为空。如果要获取的是Session中的数据,则可以使用 @SessionAttribute(“userName”) String userName来获取。
mv.setViewName(“roleDetails”) 代表返回的数据模型为roleDetails. jsp(配置里配置了.jsp)。但是在目前的前端技术中普遍使用Ajax技术,往往需要后台返回JSON数据给前端使用,这就需要修改为mv. setView(new MappingJackson2JsonView())。
mv. addObject(“role”, role)代表给数据模型添加了一个角色对象,这样就可以通过将数据渲染到视图中来呈现给用户。
那么jsp文件就可以用如下代码来呈现数据:
<c:out value="${role.id}"></c:out>
三、详解
1、接收参数
Spring MVC比较智能化,如果传递过来的参数名称和HTTP的保存一致,那么无需任何注解也可以获取参数。
示例代码:
@RequestMapping("/commonParams")
public ModelAndView commonParams(String roleName, String note){
System.out.println("roleName =>" + roleName);
System.out.println("note =>" + note);
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
如果参数名称和HTTP请求参数名称一致,那么就可以直接获取参数,这样的方式允许参数为空。
在没有任何注解的情况下,Spring MVC也有映射POJO的能力。只要将参数设置为POJO,并且POJO的属性和HTTP请求参数名称一致,那么它们就能有效传递参数。
如果参数名称和HTTP请求参数的名称不一致,则可以采用@RequestParam注解获取参数:
public ModelAndView requestParam(@RequestParam(value = "role_name", required = false) String roleName, String note){
......
}
如果参数被@RequestParam注解,那么默认情况下不能为空,如果希望允许它为空,那么要修改它的配置项required为false,代表允许参数为空。
如果参数通过URL传递,那么获取参数需要@RequestMapping和@PathVariable两个注解协作完成:
@RequestMapping("/getRole/{id}")
public ModelAndView pathVariable(@PathVariable("id") Long id){
......
}
{id}代表接收一个参数,注解@PathVariable表示从URL的请求地址中获取参数。
如要接收JSON参数,则可用如下代码实现:
public ModelAndView addRoles(@RequestBody List<Role> roleList){
......
}
注解@RequestBody表示要求Spring MVC将传递过来的JSON数组数据,转换为对应的Java类型。@RequestBody主要用来接收前端传递给后端的json字符串中的数据(请求体中的数据),GET方式无请求体,所以前端只能使用POST方式进行提交。
2、重定向
通过返回带有redirect的字符串实现重定向:
@RequestMapping("/addRole")
public String addRole(Model model, String roleName, String note){
Role role = new Role();
role.setRoleName(roleName);
role.setNote(note);
roleService.insertRole(role);
//绑定重定向数据模型
model.addAttribute("roleName", roleName);
model.addAttribute("note", note);
model.addAttribute("id", role.getId());
return "redirect:./showRoleJsonInfo.do";
}
这里的Model是一个数据模型,可以给它附上对应的数据模型,然后通过返回字符串来实现重定向的功能。
通过返回视图实现重定向:
@RequestMapping("/addRole2")
public ModelAndView addRole2(ModelAndView mv, String roleName, String note){
Role role = new Role();
role.setRoleName(roleName);
role.setNote(note);
roleService.insertRole(role);
//绑定重定向数据模型
mv.addAttribute("roleName", roleName);
mv.addAttribute("note", note);
mv.addAttribute("id", role.getId());
mv.setViewName("redirect:./showRoleJsonInfo.do");
return mv;
}
通过RedirectAttribute数据模型实现重定向(代码最简洁):
@RequestMapping("/addRole3")
public String addRole3(RedirectAttributes ra, Role role){
//绑定重定向数据模型
ra.addFlashAttribute("role", role);
return "redirect:./showRoleJsonInfo2.do";
}
使用RedirectAttributes方法后,Spring MVC会将数据保存到Session中,重定向后就会将其清除。
3、保存并获取属性参数
注解@RequestAttribute(获取一次请求的参数)
@RequestAttribute主要的作用是从HTTP的request对象中取出请求属性,只是它的范围周期是在一次请求中存在。
示例代码如下:
@RequestMapping(value = "/getRole", method = RequestMethod.GET)
public ModelAndView getRole(@RequestAttribute(value = "id", required = false) Long id){
Role role = roleService.getRole(id);
ModelAndView mv = new ModelAndView();
mv.setViewName(new MappingJackson2JsonView());
mv.addObject("role", role);
return mv;
}
注解@SessionAttributes(保存数据到HTTP的Session对象中)
在控制器中可以使用注解@SessionAttributes来设置对应的键值对,不过这个注解只能对类进行标注,不能对方法或参数注解。它可以配置属性名称或者属性类型。它的作用是当这个类被注解后,Spring MVC执行完控制器的逻辑后,将数据模型中对应的属性名称或者属性类型保存到HTTP的Session对象中。
示例代码如下:
@Controller("myController")
@RequestMapping("/attribute")
//可以配置数据模型的名称和类型,两者取或关系
@SessionAttributes(names = {
"id"}, types = {
Role.class})
public class AttributeController{
@Autowired
private RoleService roleService = null;
@RequestMapping("/sessionAttributes")
public ModelAndView sessionAttrs(Long id){
Role role = roleService.getRole(id);
ModelAndView mv = new ModelAndView();
mv.setViewName("sessionAttribute");
mv.addObject("role", role);
mv.addObject("id", id);
return mv;
}
}
注解@SessionAttribute(获取Session对象中的数据)
@RequestMapping("/sessionAttribute")
public ModelAndView sessionAttr(@SessionAttribute("id") Long id){
Role role = roleService.getRole(id);
ModelAndView mv = new ModelAndView();
mv.setViewName(new MappingJackson2JsonView());
mv.addObject("role", role);
return mv;
}
@SessionAttribute注解的参数默认不可以为空,如果需要允许为空,修改配置项required为false即可。
注解@CookieValue和注解@RequestHeader
从Cookie和HTTP请求头获取对应的请求信息
示例代码:
@RequestMapping("getHeaderAndCookie")
public String testHeaderAndCookie(@RequestHeader(value="User-Agent", required=false, defaultValue="attribute") String userAgent,
@CookieValue(value="JSESSIONID", required=true, defaultValue="MyJsessionId") String jsessionId){
System.out.println("User-Agent: " + userAgent);
System.out.println("JSESSIONID: " + jsessionId);
return "index";
}
defaultValue为默认值,当没有获取到数据时,该值取默认值。
4、拦截器
Spring要求处理器的拦截器都要实现接口HandlerInterceptor,这个接口定义了三个方法:
- preHandle:在处理器之前执行的前置方法。
- postHandle:在处理器之后执行的后置方法。
- afterCompletion:无论是否产生异常都会在渲染视图后执行的方法。
当只想实现三个拦截器中的一到两个时,只要继承这个接口,根据需要覆盖掉原有的方法就可以了。
拦截器代码示例:
public class RoleInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
System.err.println("preHandle");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception{
System.err.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception{
System.err.println("afterCompletion");
}
}
还需要进一步配置,拦截器才能为我们所用:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/role/*.do"/>
<bean class="com.ssm.chapter15.interceptor.RoleInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
用元素mvc:interceptors配置拦截器,在它里面可以配置多个拦截器。
其中class配置指定为开发的拦截器,path则是告诉Spring MVC该拦截器拦截什么请求,它使用了一个正则式的匹配。
5、验证表单
5.1、注解验证
Spring提供了对Bean的功能校验,通过注解 @Valid 标明哪个Bean需要启用注解式的验证。
注解 | 详细信息 |
---|---|
@Null | 被注释的元素必须为null |
@NotNull | 被注释的元素必须不为null |
@AssertTrue | 被注释的元素必须为true |
@AssertFalse | 被注释的元素必须为false |
@Min(value) | 被注释的元素必须为一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须为一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须为一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须为一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注释的元素的大小必须在指定的范围内 |
@Digits(integer, fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
其中@DecimalMax(value)和@Max(value) 的区别在于@DecimalMax(value)可以通过把数字设为字符串来处理非常大的数字,比如@DecimalMax(“9999999999.999999999”),而@Max(value)则不行,它只能设置正常大小的数字@Max(9999)。
示例代码:
public class Transaction{
@NotNull//不能为空
private Long productId;
@Future//只能是将来的日期
@DateTimeFormat(pattern = "yyyy-MM-dd")//日期格式化转换
@NotNull//不能为空
private Date date;
@Min(1)//最小值为1
@Max(100)//最大值为100
@NotNull//不能为空
private Integer quantity;
@NotNull//不能为空
@DecimalMax("500000.00")//最大金额为5万元
@DecimalMin("1.00")//最小交易金额1元
private Double amount;
//邮件
@Pattern(//正则式
regexp = "^([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)*@" + "([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)[\\.][A-Za-z]{2,3}([\\.][A-Za-z]{2})?$",
//自定义消息提示
message="不符合邮件格式")
private String email;
//Size(min = 0, max = 256)//0到255个字符
private String note;
}
这样就定义了一个POJO,用以接收表单的信息,并且给每一个字段加入了对应的校验,它会生成默认的错误信息。
用控制器完成表单的校验:
@Controller
@RequestMapping("/validate")
public class ValidateController{
@RequestMapping("/validate")
public class ValidateController{
@RequestMapping("/annotation")
public ModelAndView annotationValidate(@Valid Transaction trans, Errors errors){
//是否存在错误
if(errors.hasErrors()){
//获取错误信息
List<FieldError>errorList = errors.getFieldErrors();
for(FieldError error : errorList){
//打印字段错误信息
System.err.println("fied :" + error.getField() + "\t" + "msg:" + error.getDefaultMessage());
}
}
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
}
}
使用 @Valid 标注,表明这个Bean将会被检验,而另一个类型为Errors的参数则是用于保存是否存在错误信息的,当采用JSR303规范进行校验后,它会将错误信息保存到这个参数中,进入方法后使用其hasErrors方法,便能够判断其验证是否出现错误。
5.2、使用验证器
6、文件上传
前端代码示例:
<form method="post" action="./file/upload.do" enctype="multipart/form-data">
<input type="file" name="file" value="请选择上传的文件"/>
<input type="submit" value="提交"/>
</form>
注意,要把enctype定义为"multipart/form-data",否则Spring MVC会解析失败,有了它就会提交到URL为./file/upload.do的请求上。
控制器代码示例:
@Controller
@RequestMapping("/file")
public class FileController{
//使用MultipartFile
@RequestMapping("/uploadMultipartFile")
public R uploadMultipartFile(MultipartFile file){
R request = new R();
if(!file.isEmpty()) {
String fileName = file.getOriginalFilename;
file.transferTo(new File("F:\\workPicture\\" + fileName));
request.success();
}
else {
request.false();
}
return request;
}
}
使用MultipartFile和Part其中之一就可以实现文件上传,它们的好处是把代码从Servlet API中解放出来,这体现了spring的思维,高度的解耦性,同时也简化了许多关于文件的操作。
springBoot默认的配置中,上传文件最大为1M,同时上传的文件数量最多为10个,如要修改默认配置可以在配置文件中添加:
#上传文件最大为10M
spring.servlet.multipart.max-file-size=10MB
#整个的上传文件最大为100MB
spring.servlet.multipart.max-request-size=100MB