基本介绍
SpringMVC是Spring这个框架的一个模块 即Web MVC
该模块对Servlet进行了封装 简化了Servlet操作 是Controller层的一个解决方案
代码实现
导包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
配置spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.qfedu.edu.controller" />
</beans>
配置web.xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
Controller
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/test.action")
@ResponseBody
public Object test(){
return "buliyat....";
}
}
测试
参数封装
键值对
@RequestMapping("/parameter01.action")
@ResponseBody
public Object parameter01(String username,String password){
System.out.println("username:"+username+"---password:"+password);
return "buliyat...";
}
对象
@RequestMapping("/parameter02.action")
@ResponseBody
public Object parameter02(User user){
System.out.println("username:"+user);
return "buliyat...";
}
数组
@RequestMapping("/parameter03.action")
@ResponseBody
public Object parameter03(String[] habbits){
System.out.println("username:"+ Arrays.toString(habbits));
return "buliyat...";
}
集合
@RequestMapping("/parameter04.action")
@ResponseBody
public Object paramete0r5(UserList userList){ // private List<User> users;
System.out.println("user:"+ userList);
return "buliyat...";
}
<form action="/user/parameter04.action" method="post">
用户名:<input type="text" name="users[0].username"> <br>
密码:<input type="text" name="users[0].password"> <br>
用户名:<input type="text" name="users[1].username"> <br>
密码:<input type="text" name="users[1].password"> <br>
用户名:<input type="text" name="users[2].username"> <br>
密码:<input type="text" name="users[2].password"> <br>
<input type="submit" name="提交"> <br>
</form>
同址异参
@RequestMapping("/parameter05.action")
@ResponseBody
public Object parameter05(UserAndAdmin userAndAdmin){
System.out.println("user:"+ userAndAdmin.getUser());
System.out.println("admin:"+ userAndAdmin.getAdmin());
return "buliyat...";
}
用户数据:<br>
<form action="/user/parameter05.action" method="post">
用户名:<input type="text" name="user.username"> <br>
密码:<input type="text" name="user.password"> <br>
<input type="submit" name="提交"> <br>
</form>
管理员数据:<br>
<form action="/user/parameter05.action" method="post">
用户名:<input type="text" name="admin.username"> <br>
密码:<input type="text" name="admin.password"> <br>
<input type="submit" name="提交"> <br>
</form>
JSON
@RequestMapping("/parameter06.action")
@ResponseBody
public Object parameter06(@RequestBody User user){
System.out.println("user:"+ user);
return new User(1,"buliyat","123");
}
<!-- 配置消息转换器 -->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 返回一个字符串非Java对象的时候使用的消息转换器 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8"/>
</bean>
<!-- 返回Java对象转换成JSON格式的时候使用的消息转换器 -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json;charset=UTF-8"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
返回值
Jsp页面
@RequestMapping("/back01.action")
public String back01(){
return "/buliyat.jsp";
}
@RequestMapping("/back02.action")
public void back02(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/buliyat.jsp").forward(req,resp);
}
转发和重定向
@RequestMapping("/back01.action")
public String back01(){
return "redirect:http://www.baidu.com"; // 重定向
}
@RequestMapping("/back02.action")
public String back02(){
return "http://www.baidu.com"; // 转发
}
Model
@RequestMapping("/back01.action")
public String back01(Model model){
model.addAttribute("username","buliyat");
return "/buliyat.html";
}
ModelAndView
@RequestMapping("/back01.action")
public ModelAndView back01(ModelAndView modelAndView){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/buliyat.html");
model.addAttribute("username","buliyat");
return ModelAndView;
}
JSON
@RequestMapping("/back01.action")
@ResponseBody
public Object back01(){
return new User(1,"buliyat","123");
}
方法约束
@GetMapping // 只能使用get方法请求
@PostMapping // 只能使用post方法请求
@PutMapping // 只能使用put方法请求
@DeleteMapping // 只能使用delete方法请求
@ResponseBody // 返回格式为JSON
public String method01(){
return "/buliyat.jsp";
}
拦截器
Intercepter(Spring Web MVC)
public class MyInterceptor implements HandlerInterceptor {
// 控制器方法执行前 认证 鉴权
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("------------preHandle------------");
return true;
}
// 控制器方法执行后 干预结果
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
modelAndView.addObject("username","铁蛋");
System.out.println("------------postHandle------------");
}
// 控制器方法出现异常时
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if (ex != null) {
System.out.println("------------afterCompletion------------");
}
}
}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<mvc:exclude-mapping path="/user/method01.action"/>
<mvc:exclude-mapping path="/user/method01.action"/>
<bean class="com.qcy.buliyat.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
Intercepter(Spring Framework)
public class MyWebRequestInterceptor implements WebRequestInterceptor {
public void preHandle(WebRequest webRequest) throws Exception {
System.out.println("--MyWebRequestInterceptor----preHandle--------");
}
public void postHandle(WebRequest webRequest, ModelMap modelMap) throws Exception {
System.out.println("--MyWebRequestInterceptor----postHandle-------");
public void afterCompletion(WebRequest webRequest, Exception e) throws Exception {
if (e != null) {
System.out.println("--MyWebRequestInterceptor----afterCompletion-");
}
}
}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/dept/add.action"/>
<bean class="com.qcy.buliyat.interceptor.MyWebRequestInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
全局异常
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:bean-*.xml</param-value>
</context-param>
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
">
<!-- 设置扫描的包 -->
<context:component-scan base-package="com.buliyat.qcy" />
</beans>
全局异常
@Component
public class GlobleException implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse resp, Object o, Exception e) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 100);
jsonObject.put("message", "出现异常了");
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = null;
try {
writer = resp.getWriter();
writer.write(jsonObject.toJSONString());
writer.flush();
writer.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return null;
}
}
上传下载
上传
导包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
spring-mvc.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSizePerFile" value="100000000"></property>
<property name="maxUploadSize" value="200000000000"></property>
</bean>
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/user/fileUpload.action" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"> <br>
密 码:<input type="text" name="password"> <br>
头 像:<input type="file" name="file"> <br>
<input type="submit" name="提交"> <br>
</form>
<hr/>
</body>
</html>
Controller
@PostMapping("/fileUpload.action")
@ResponseBody
public Object fileUpload(@RequestParam("file") MultipartFile file,User user) throws IOException {
System.out.println("用户数据:" + user);
file.transferTo(new File("G:\\buliyat.png"));
return "文件上传成功";
}
下载
@RequestMapping("/moethod01.action")
public void moethod01(HttpServletResponse resp) throws IOException {
resp.setHeader("Content-Disposition","attachment;filename=xxxx.jpg");
File file = new File("G:\\buliyat.png");
FileInputStream in = new FileInputStream(file);
ServletOutputStream out = resp.getOutputStream();
byte[] buf=new byte[8192];
int length=0;
while ((length=in.read(buf))!=-1){
out.write(buf,0,length);
}
in.close();
out.close();
}
@RequestMapping("/moethod02.action")
public ResponseEntity<byte[]> moethod02() throws IOException {
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("Content-Disposition","attachment;filename=xxxx.jpg");
return new ResponseEntity<byte[]>(FileCopyUtils.copyToByteArray(new File("G:\\buliyat.png")),httpHeaders, HttpStatus.OK);
}
前置后置
前置处理
@ControllerAdvice
public class MyRequestBodyAdviser implements RequestBodyAdvice {
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}
// RequestBody之前执行
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
System.out.println("解密了.....");
return httpInputMessage;
}
// RequestBody之后执行
public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
System.out.println("已经将JSON转换成了Java对象之后 执行的方法");
return o;
}
// 传递了空参数
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
}
后置处理
@ControllerAdvice
public class MyResponseAdvice implements ResponseBodyAdvice {
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}
// ResponseBody之后执行
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
System.out.println("返回数据加密了....");
return o;
}
}
运行原理
-
客户端(浏览器)发送请求, DispatcherServlet拦截请求。
-
DispatcherServlet 根据请求信息调用 HandlerMapping 。HandlerMapping 根据 URL 去匹配查找能处理的 Handler(也就是我们平常说的 Controller 控制器) ,并会将请求涉及到的拦截器和 Handler 一起封装。
-
DispatcherServlet调用 HandlerAdapter适配器执行 Handler 。
-
Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给DispatcherServlet,`ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model 是返回的数据对象,View 是个逻辑上的 View。
-
ViewResolver 会根据逻辑 View查找实际的 View。
-
DispaterServlet 把返回的 Model传给 View(视图渲染)。
-
把 View 返回给请求者(浏览器)