SpringMVC
概述
SpringMVC是一种基于Java的实现MVC设计模型
的请求驱动类型的轻量级Web框架
,属于SpringFrameWork的后续产品,已经融合在Spring Web Flow 中。
快速入门
需求:客户端发起请求,服务端接收请求,执行逻辑并进行视图跳转
开发步骤:
-
导入SpringMVC坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.9.RELEASE</version> </dependency>
-
配置SpringMVC核心控制器DispathcerServlet
<!--配置SpringMVC的前端控制器--> <servlet> <servlet-name>DispatherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--启动时访问--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatherServlet</servlet-name> <!--缺省值全访问控制器--> <url-pattern>/</url-pattern> </servlet-mapping>
-
创建Controller类和视图界面
-
使用注解配置Controller类中业务方法的映射地址
//将此类放入Spring容器中 @Controller public class UserController { //SpringMVC映射此类 @RequestMapping("/quick") public String save(){ System.out.println("Controller save Running~~~"); //跳转界面 return "success.jsp"; } }
-
配置SpringMVC核心文件spring-mvc.xml
<!--controller的组件扫描--> <context:component-scan base-package="controller"/>
SpringMVC组件解析
SpringMVC注解解析
@RequestMapping("地址")
用户建立URL域请求处理方法之间的关系,可以应用在类上或方法上
- 类上:请求URL的第一级访问目录,此出不写就相当于根目录
- 方法上:请求URL的第二级访问目录,与类上的使用@RequestMapping标注的一级目录一起组成访问虚拟路径
属性
- value:用户指定请求的URL,它和path属性的作用是一样的
- method:用于指定请求的方式
- params:用于指定限制请求参数的条件,它支持简单的表达式,要求请求参数的key和value必须配置的一模一样
- 例:
- params = {"username"} ,表示请求参数必须有username
- params = {"money!100"} ,表示请求参数中的money不能是100
//将此类放入Spring容器中
@Controller
public class UserController {
//SpringMVC映射此类
@RequestMapping("/quick")
public String save(){
System.out.println("Controller save Running~~~");
//跳转界面
return "success.jsp";
}
}
return关键字:
- 属性:
- redirect:重定向
return "redirect:页面名"
- forward:转发
return "forward:页面名"
- redirect:重定向
- 默认是转发(forward)
SpringMVC-XML配置
<!--配置内部资源配置解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--资源前缀:/jsp/success.jsp-->
<property name="prefix" value="/jsp/" />
<!--资源后缀:success.jsp ==> success-->
<property name="suffix" value=".jsp" />
</bean>
SpringMVC数据响应
响应方式:
-
页面跳转
-
直接返回字符串
-
此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转
return "success";
<!--资源前缀:/jsp/success.jsp--> <property name="prefix" value="/jsp/" /> <!--资源后缀:success.jsp ==> success--> <property name="suffix" value=".jsp" />
转发资源地址:
/jsp/success.jsp
-
-
通过ModelAndView对象返回
-
ModelAndView
//SpringMVC映射此类 @RequestMapping("/quick1") public ModelAndView save1(){ /* model:模型,封装数据 view:视图,展示界面 */ ModelAndView modelAndView = new ModelAndView(); //设置视图模型 modelAndView.addObject("username","IMAU"); //设置视图名,与return "success";功能一致 modelAndView.setViewName("success"); return modelAndView; }
-
ModelAndView参数型:参数会由SpringMVC框架注入
//SpringMVC映射此类 @RequestMapping("/quick2") public ModelAndView save2(ModelAndView modelAndView){ modelAndView.addObject("username","IMAU"); modelAndView.setViewName("success"); return modelAndView; }
-
Model与String拼接型:参数会由SpringMVC框架注入
//SpringMVC映射此类 @RequestMapping("/quick3") public String save3(Model model){ model.addAttribute("username","内蒙古农业大学"); return "success"; }
-
-
-
回写数据
-
直接返回字符串
-
通过SpringMVC框架注入的Response对象,使用
response.getWriter().print("")
回写数据,此时不需要视图跳转,业务方法返回值为void
//SpringMVC映射此类 @RequestMapping("/quick5") public void save5(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf8"); response.getWriter().print("Hello 内蒙古"); }
-
将字符串直接
return
返回,但此时需要通过@ResponseBody
注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体上返回//SpringMVC映射此类 @ResponseBody //告诉SpringMVC框架不进行视图跳转,直接数据响应 @RequestMapping("/quick6") public String save6() throws IOException { return "Hello 内蒙古"; }
-
-
返回对象或集合
-
添加MVC注解驱动:会调用Jackson直接将对象转为json格式
<!--mvc注解驱动--> <mvc:annotation-driven/>
-
编写方法
//SpringMVC映射此类 @ResponseBody @RequestMapping("/quick8") public User save8() throws IOException { User user = new User(); user.setName("iimau"); user.setAge(20); //使用Jackson将对象转为json格式返回 return user; }
-
-
SpringMVC获得请求数据
SpringMVC接收类型的参数
-
基本类型参数
-
Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配
http://localhost:8080/quick9?username=zhangsan&age=20
//SpringMVC映射此类 @ResponseBody @RequestMapping("/quick9") public void save9(String username,int age) throws IOException { System.out.println(username+":"+age); } zhangsan:20
-
-
POJO类型参数
-
Controller中的业务方法的POJO参数的属性名要与请求参数的name一致,参数值会自动映射匹配
http://localhost:8080/quick10?username=lisi&age=30
//SpringMVC映射此类 @ResponseBody @RequestMapping("/quick10") public void save10(User user) throws IOException { System.out.println(user); } User{username='lisi', age=30}
-
-
数组类型参数
-
Controller中的业务方法的数组名称要与请求参数的name一致,参数值会自动映射匹配
http://localhost:8080/quick11?strs=aaa&strs=bbb&strs=ccc
//SpringMVC映射此类 @ResponseBody @RequestMapping("/quick11") public void save11(String[] strs) throws IOException { System.out.println(Arrays.asList(strs)); } [aaa, bbb, ccc]
-
-
集合类型参数
-
获得集合参数时,要将集合参数包装到POJO中才可以
新建一个POJO包装集合
public class Vo { private List<User> userList; public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } @Override public String toString() { return "Vo{" + "userList=" + userList + '}'; } }
编写JSP文件
<body> <form action="${pageContext.request.contextPath}/quick13" method="post"> <input type="text" name="userList[0].username"><br> <input type="text" name="userList[0].age"><br> <input type="text" name="userList[1].username"><br> <input type="text" name="userList[1].age"><br> <input type="submit" value="提交"> </form> </body>
编写接收类
@ResponseBody @RequestMapping("/quick13") public void save13(Vo vo) throws IOException { System.out.println(vo); } Vo{userList=[User{username='zhangsan', age=18}, User{username='wangwu', age=80}]}
-
在使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用
@RequestBody
可以直接接收集合数据而无需使用POJO进行包装<script> var userlist = new Array(); userlist.push({username:"zhangsan",age:20}) userlist.push({username:"lisi",age:40}) $.ajax({ type:"POST", url:"${pageContext.request.contextPath}/quick12", data:JSON.stringify(userlist), contentType:"application/json;charset=utf-8" }); </script>
//SpringMVC映射此类 @ResponseBody @RequestMapping("/quick12") public void save12(@RequestBody List<User> userList) throws IOException { System.out.println(userList); } [User{username='zhangsan', age=20}, User{username='lisi', age=40}]
-
静态资源访问
两种方式:
<mvc:resources mapping="" location="" />
mapping
:服务端找资源的地址location
:资源所在目录
<mvc:default-servlet-handler/>
- 在提交时SpringMVC帮你找静态资源,如果找不到,会交给原有容器进行查找
请求数据乱码问题
使用过滤器进行编码的过滤
<!--配置全局过滤器Filter-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
参数绑定注解@RequestParam
当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定
参数:
- value:请求参数名称
- required:在指定的请求参数是否必须包括,默认是true,如果参数没有value则报错
- defaultValue:当没有指定请求参数时,则使用默认值复制
请求参数:http://localhost:8080/quick14?name=zhangsan
@ResponseBody
@RequestMapping("/quick14")
public void save14(@RequestParam("name") String username) throws IOException {
System.out.println(username);
}
zhangsan
请求参数:http://localhost:8080/quick14
@ResponseBody
@RequestMapping("/quick14")
public void save14(@RequestParam(value = "name",required = false,defaultValue = "lisi") String username) throws IOException {
System.out.println(username);
}
lisi
获得Restful风格的参数
Restful是一种架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更容易实现缓存机制
Restful风格的请求是使用URL+请求方式
表示一次性达到目的,HTTP协议里面四个表示操作方式的动词如下:
- GET:用于获取资源
- POST:用于新建资源
- PUT:用于更新资源
- DELETE:用于删除资源
在SpringMVC中可以使用占位符进行参数绑定,/user/1
可以写成/user/{id}
,占位符{id}
映射的就是1的值,在业务方法中我们可以使用@PathVariable
注解进行占位符的匹配获取工作,注意:占位符的名字必须与@PathVariable
的一致
请求URL:http://localhost:8080/quick15/zhangsan
@ResponseBody
@RequestMapping("/quick15/{name}")
public void save15(@PathVariable("name") String username) throws IOException {
System.out.println(username);
}
zhangsan
自定义类型转换器
开发步骤:
-
定义转换器类实现Converter接口
//Converter<R,T> R:待转换的类型 T:想转换的类型 public class DateConverter implements Converter<String, Date> { @Override public Date convert(String dateStr) { //使用SimpleDateFormat进行格式转换 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-dd-mm"); Date date = null; try { //调用parse方法 date = simpleDateFormat.parse(dateStr); } catch (ParseException e) { e.printStackTrace(); } //返回date return date; } }
-
在配置文件中声明转换器
<!--声明转换器--> <bean id="converService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="converter.DateConverter"/> </list> </property> </bean>
-
在
<annotation-driven>
中引用转换器<mvc:annotation-driven conversion-service="converService"/>
获取请求头
@RequestHeader
使用@RequestHeader获得请求头信息
- value:请求头名称
- required:是否必须携带此请求头
@ResponseBody
@RequestMapping("/quick17")
public void save17(@RequestHeader(value = "User-Agent",required = true) String Header) throws IOException {
System.out.println(Header);
}
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
@CookieValue
获得指定的Cookie值
- value:指定Cookie的名称
- required:是否必须携带此Cookie
@ResponseBody
@RequestMapping("/quick18")
public void save18(@CookieValue(value = "JESSIONID") String jessionID) throws IOException {
System.out.println(jessionID);
}
文件上传
文件上传三要素
- 表单项type="file"
- 表单提交方式为"POST"
- 表单的enctype属性是多部分表单形式,及enctype="multipart/form-data"
<body>
<form action="${pageContext.request.contextPath}/quick19" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
文件<input type="file" name="upload"><br>
<input type="submit" value="提交">
</form>
</body>
单文件上传步骤
-
导入fileupload和io坐标
-
配置文件上传解析器
<!--配置文件上传解析器--> <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="resolver"> <property name="defaultEncoding" value="UTF-8"/> <!--上传文件总大小--> <property name="maxUploadSize" value="500000"/> </bean>
-
编写文件上传代码
参数名称必须与表单name一致
@ResponseBody @RequestMapping("/quick19") public void save19(String username, MultipartFile upload) throws IOException { //获得上传文件名称 String filename = upload.getOriginalFilename(); //保存文件 upload.transferTo(new File("E:\\"+filename)); }
多文件上传:服务端使用MultipartFile[]
数组接收即可
SpringMVC拦截器
相当于Filter,用于对处理器进行预处理和后处理
-
拦截器和过滤器的区别
区别 过滤器 拦截器 使用范围 是servlet规范的一部分,任何JavaWeb工程都能使用 是SpringMVC框架自己的,只有SpringMVC框架的工程才能使用 拦截范围 在url-pattern中配置了/*之后,可以拦截所有访问的资源 只会拦截访问的控制器方法,如果访问的是jsp、html、css、image、js是不会拦截的 -
快速入门
-
创建拦截器实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor { //在目标方法执行前执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String username = request.getParameter("username"); if (username.equals("zhangsan")) { return true; } else { request.getRequestDispatcher(request.getContextPath()+"jsp/list.jsp").forward(request,response); } //true:放行 false:不放行 return false; } //在目标方法执行之后,视图返回之前执行 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("username","内蒙古大学"); } //整个流程都执行完毕后执行 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after...."); } }
-
配置拦截器
<mvc:interceptors> <mvc:interceptor> <!--对那些资源执行拦截操作--> <mvc:mapping path="/**"/> <bean class="interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
-
测试拦截器的拦截效果
-
-
拦截器方法说明
方法名 说明 preHandle() 方法在请求处理之前调用,返回值为false时表示请求结束,后面的方法都不会执行,当为true的时候,会继续调用下一个Interceptor的preHandle方法 postHandle() 该方法是在当前请求进行处理之后被调用,前提是preHandle返回值为true,且在DispatcherServlet进行视图返回渲染之前被调用,所以可以处理ModelAndView对象进行操作 afterCompletion() 该方法在整个请求结束后执行
SpringMVC异常处理机制
-
异常分类:预期异常、运行时异常
-
处理异常的两种方式
SimpleMappingExceptionResolver
:简单异常处理器HandlerExceptionResolver
:自定义异常处理器
-
简单异常处理器
//强制转换错误 @ResponseBody @RequestMapping("/ex2") public void ex2(){ Object str = "Zhang"; Integer a = (Integer)str; } //除0错误 @ResponseBody @RequestMapping("/ex1") public void ex1(){ int i = 1/0; }
<!--配置异常处理--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" > <!--默认异常,value为跳转的界面--> <property name="defaultErrorView" value="error" /> <!--设置指定异常,Map形式可以设置多个--> <property name="exceptionMappings"> <map> <entry key="java.lang.ClassCastException" value="CastError"/> </map> </property> </bean>
-
自定义异常处理器
-
创建异常处理器类实现
HandleExceptionResolver
instanceof
严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例public class MyException implements HandlerExceptionResolver { /* 参数:Exception:异常对象 返回值:ModelAndView:跳转到错误视图信息 */ @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView = new ModelAndView(); /* instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例 */ if (e instanceof ClassCastException){ modelAndView.addObject("info","强制转换错误"); } modelAndView.setViewName("error"); return modelAndView; } }
-
配置异常处理器
<!--自定义异常处理--> <bean class="resolver.MyException"/>
-
编写异常页面
-