SpringMVC的工作原理(底层Servlet的工作流程)
- DispatcherServlet
- HandlerMapping ,返回值 HandlerExecutionChain
- HandlerAdapter
- ViewResolver
- View
~~老版本(过去式)
一、搭建springmvc
第一步:配置打包方式
<packaging>war</packaging>
第二步:重新定义webapp目录
第三步:导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
第四步:构建不同类型的实现类/继承类
1. 实现接口 HttpRequestHandler
package com.qf.mvc01.controller;
import org.springframework.web.HttpRequestHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class BookController implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("hello book");
}
}
2. 实现接口 Controller
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView("hello");
mv.addObject("msg","hello springmvc");
return mv;
}
}
(1). 其前端校验例子
<%--
Created by IntelliJ IDEA.
User: lyz
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>${msg}</h1>
</body>
</html>
3. 继承 HttpServlet
package com.qf.mvc01.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class UserController extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
第五步:配置 resources(spring-servlet)
1. 将 各Controller 注册到 Spring 容器中
2. 配置 处理器映射器 HandlerMapping
3. 配置 处理器适配器 HandlerAdapter
4. 配置视图解析器 ViewResolver
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.qf.mvc01.controller.HelloController" id="/hello"/>
<bean class="com.qf.mvc01.controller.BookController" id="bookController"/>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/book">bookController</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
第六步:在 web.xml 中加载 spring-servlet.xml配置文件信息
1. 加 spring-servlet.xml 配置文件信息
2. 同时配置 springmvc 拦截器
<?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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
~~新(现在时)
一、搭建springmvc
第一步:配置打包方式
<packaging>war</packaging>
第二步:重新定义webapp目录
第三步:导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
第四步:构建不同类型的实现类/继承类
给创建的 Controller 类上添加 @Controller注解
package com.qf.mvc02.controller;
import org.springframework.stereotype.Controller;
@Controller
public class TestController {
}
第五步:配置 resources(spring-servlet)
1. 添加 springframework 的 xmlns
2. 通过注解扫描注册 Controller
3. 同时配置 处理器映射器、处理器适配器
4. 配置视图解析器 ViewResolver
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.qf.mvc02.controller"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
第六步:配置 web.xml 配置
1. 配置 spring-servlet.xml 配置文件信息
2. 配置过滤器
3. 配置请求体乱码过滤器
<?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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
~~!!相关知识
一、请求窄化
1. 实例Controller类
package com.qf.mvc02.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays;
@Controller
@RequestMapping("/book")
public class BookController {
@GetMapping("/add")
public ModelAndView addBook(){
System.out.println("===================");
return new ModelAndView("book");
}
@DeleteMapping("/add")
public ModelAndView deleteBook(){
System.out.println("--------------------");
return null;
}
@PostMapping("/add")
public void addBook(String name,String author,Double price,String[] tags){
System.out.println("name = " + name);
System.out.println("author = " + author);
System.out.println("price = " + price);
System.out.println("tags = " + Arrays.toString(tags));
}
}
2. 实例 jsp
<%--
Created by IntelliJ IDEA.
User: lyz
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>book.jsp</h1>
<form action="/m02/book/add" method="post">
<table>
<tr>
<td>书名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>作者:</td>
<td><input type="text" name="author"></td>
</tr>
<tr>
<td>价格:</td>
<td><input type="text" name="price"></td>
</tr>
<tr>
<td>标签:</td>
<td>
<input type="checkbox" name="tags" value="小说">小说
<input type="checkbox" name="tags" value="散文">散文
<input type="checkbox" name="tags" value="科技">科技
<input type="checkbox" name="tags" value="工程">工程
<input type="checkbox" name="tags" value="数学">数学
</td>
</tr>
<tr>
<td><input type="submit" value="添加"></td>
</tr>
</table>
</form>
</body>
</html>
二、方法返回值
1. java实例:方法hello1 --> hello6(见三内)
2. 实例 jsp(见三内)
三、方法参数
1. java实例:方法hello7 --> hello12
package com.qf.mvc02.controller;
import com.qf.mvc02.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/hello")
public String addUser(Model model){
model.addAttribute("hello","hello springmvc");
return "user";
}
@GetMapping("/hello2")
public String hello2(){
return "forward:/user/hello";
}
@GetMapping("/hello3")
public String hello3(){
return "redirect:/user/hello";
}
@GetMapping(value = "/hello4",produces = "text/html;charset=utf-8")
@ResponseBody
public String hello4(){
return "你好hello4";
}
@GetMapping("/hello5")
@ResponseBody
public void hello5(){
System.out.println("===========");
}
@GetMapping("/hello6")
public void hello6(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException, ServletException {
response.getWriter().write("hello");
request.setAttribute("hello", "hello");
request.getRequestDispatcher("/WEB-INF/jsp/user.jsp").forward(request,response);
}
@GetMapping("/hello7")
@ResponseBody
public void addUser(@RequestParam(value = "name",defaultValue = "java") String username, String address,@RequestParam Integer age){
System.out.println("username = " + username);
System.out.println("address = " + address);
System.out.println("age = " + age);
}
@GetMapping("/hello8")
@ResponseBody
public void addUser2(User user){
System.out.println("user = " + user);
}
@GetMapping("/hello9/{userId}")
@ResponseBody
public void getUserById(@PathVariable("userId") Long aaa){
System.out.println("aaa = " + aaa);
}
@GetMapping("/hello10/{userId}/{username}")
@ResponseBody
public void getUserById2(@PathVariable("userId") Long aaa,@PathVariable String username){
System.out.println("username = " + username);
System.out.println("aaa = " + aaa);
}
@PostMapping("/hello11")
@ResponseBody
public void hello11(String username,String address,Integer age ){
System.out.println("username = " + username);
System.out.println("address = " + address);
System.out.println("age = " + age);
}
@PostMapping("/hello12")
@ResponseBody
public void hello12(User user){
System.out.println("user = " + user);
}
}
2. 实例 jsp
<%--
Created by IntelliJ IDEA.
User: lyz
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>user.jsp</h1>
<h1>${hello}</h1>
</body>
</html>
四、存到 session 中
1. Controller 的 java 实例
package com.qf.mvc02.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
@Controller
@SessionAttributes({"name"})
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView("hello");
mv.addObject("msg","hello mvc02");
return mv;
}
@GetMapping("/hello2")
@ResponseBody
public void hello2(String name, Model model){
model.addAttribute("name",name);
System.out.println("name = " + name);
}
@GetMapping("/hello3")
@ResponseBody
public void hello3(@SessionAttribute("name") String name){
System.out.println("name = " + name);
}
@GetMapping("/hello4")
@ResponseBody
public void hello4(SessionStatus status){
status.setComplete();
}
}
2.实例 jsp
<%--
Created by IntelliJ IDEA.
User: lyz
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>${msg}</h1>
</body>
</html>
五、静态资源访问 的三种策略
1. 第一种:改接口名字
优点:相对访问高效(因为以 .do 结尾的都是 DispatcherServlet 的请求)
缺点:麻烦,需要每个接口都改名字
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2. 第二种:配置一个默认的处理器
这里额外添加一个默认的处理器,如果 HandlerMapping 找不到请求路径所对应的处理器,那么使用这个默认的处理器,这个默认的处理器会去本地文件夹中查找是否存在对应的资源
本质:运用的是重定向
优点:不需要像第一种方法哪有去改每个接口名
缺点:每个请求都要经过处理器,所以相对而言效率会下降
<mvc:default-servlet-handler/>
3. 第三种:配置资源
没用用处理器,只是进入 DispatcherServlet 中,去区分以下是静态资源还是动态资源
优点:简单快捷
缺点:(我还不知道)
<mvc:resources mapping="/**" location="/"/>
六、jackson
添加依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0</version>
</dependency>
1. 返回json的情况
(1). 核心关键 HttpMessageConverter
* HttpMessageConverter
* 1.将接口方法返回值的对象转为 JSON/XML
* 2.将请求提交的 JSON 或者 XML 字符串转为一个 Java 对象
*
* 无论我们使用哪种 JSON 解析器,都需要配置 HttpMessageConverter
*
* 但是,对于 jackson 和 gson,系统默认(springframework)已经给我们配置好了,所以我们现在不配置也可以使用
*
(2). 参用注解
//这些地方,注解的作用,都是两方面的,对象 -> JSON 和 JSON ->对象都会用到这些注解配置
(序列化和反序列化都会用到所配置的注解,即在两过程中功能需求都会生效)
@JsonIgnore 生成 JSON 的时候,忽略被注解属性@JsonProperty(……) 生成 JSON 的时候,该字段名称为 ……@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai") 生成 JSON 的时候,要求转换为特定形式的时间,同时配置时区
public class Book {
@JsonIgnore
private Integer id;
@JsonProperty("bookName")
private String name;
private String author;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai")
private Date publishDate;
}
(3). jackson的 自定义信息转换器(MappingJackson2HttpMessageConverter)
(时间属性配置全局注解)
在 spring-servlet.xml 内配置该内容,
通过该配置,可以使得全体实体类的时间类型属性,在序列化后都显示为yyyy-MM-dd HH:mm:ss 该样式,
但是同样的,在传参发送请求体的时候,也要按照该样式提交数据,不然反序列化过程中就会报错(报400错误“参数转换出错”)
<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="httpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" id="httpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg name="pattern" value="yyyy-MM-dd HH:mm:ss"/>
</bean>
</property>
</bean>
</property>
</bean>
2. 提交的参数时json的情况
给方法中的形参类型前加上 @RequestBody
* @RequestBody 表示将请求体中的内容,通过 HttpMessageConverter 自动转为参数对象
* (将请求体中的内容,映射到形参的对象中,形参对象的类型按情况选择,
* ①如果请求体中的内容可以映射成实体对象,那类型就用实体对象的,
* ②如果请求体中的内容,只是简简单单的 String,那就用 String 类型
* ③如果请求体中的内容,是 实体对象数组,那参数类型就用实体对象数组[] 去接收)
/实例如下/
@PostMapping("/book")
@ResponseBody
public void addBook(@RequestBody String book){
System.out.println("book = " + book);
}
七、gson
添加依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
1. json 解析器顺序
默认情况 jackson->gson->jsonb (前提是都导入了相关依赖)
若有自己手动配置的 HttpMessageConverter ,则手动配置的优先
* 如果当前项目中同时存在多个 json 解析器,默认情况下,选择顺序依次是 jackson->gson->jsonb
* 当然,如果自己手动配置了 HttpMessageConverter,则按照自己配置的来
2. gson的 自定义信息转换器(GsonHttpMessageConverter)
(时间属性配置全局注解)
这里调用到 GsonFactoryBean,来生成一个 Gson 对象,用于在 xml 中配置
<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="httpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter" id="httpMessageConverter">
<property name="gson">
<bean class="org.springframework.http.converter.json.GsonFactoryBean">
<property name="dateFormatPattern" value="yyyy-MM-dd HH:mm:ss"/>
</bean>
</property>
</bean>
八、fastjson
添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.21</version>
</dependency>
1. fastjson的 自定义信息转换器(FastJsonHttpMessageConverter)
<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="httpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean class="com.alibaba.fastjson2.support.spring.http.converter.FastJsonHttpMessageConverter" id="httpMessageConverter">
<property name="fastJsonConfig">
<bean class="com.alibaba.fastjson2.support.config.FastJsonConfig">
<property name="dateFormat" value="yyyy-MM-dd HH:mm:ss"/>
</bean>
</property>
<property name="defaultCharset">
<bean class="sun.nio.cs.UTF_8"/>
</property>
<property name="supportedMediaTypes">
<value>application/json;charset=utf-8</value>
</property>
</bean>
?
? 自定义参数类型转换
json 格式的参数不需要手动配置 DateConverter(自定义参数类型转换器)
key-value 格式的参数需要手动配置相应的 DateConverter
0. 举例的业务请求
举例的:业务方法
@PostMapping("/book2")
@ResponseBody
public void addBook2(Date publishDate){
System.out.println("publishDate = " + publishDate);
}
1. 自定义参数类型转换的类
举例:自定义 DateConverter 用于转换,前端传递过来的 Date 数据类型对象
package com.qf.mvc03.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String, Date> {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String source) {
try {
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
2. 注册到spring容器中
举例:将 DateConverter 注册到 Spring 容器中
<bean class="com.qf.mvc03.converter.DateConverter" id="dateConverter"/>
3. 配置参数类型转换Bean(FormattingConversionServiceFactoryBean)
配置 FormattingConversionServiceFactoryBean
<mvc:annotation-driven conversion-service="formattingConversionServiceFactoryBean">
<mvc:message-converters>
<ref bean="httpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="formattingConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="dateConverter"/>
</set>
</property>
</bean>
4. 同时需要在 mvc:annotation-driven 中引入
同时需要在mvc:annotation-driven 中引入
<mvc:annotation-driven conversion-service="formattingConversionServiceFactoryBean">
<mvc:message-converters>
<ref bean="httpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
九、全局异常处理
导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
1. 第一种:实现接口
(1). (创建 全局异常处理类 实现) HandlerExceptionResolver 接口
? (接口方法,都会被封装成一个 HandlerMethod )
? (返回的是 ModelAndView )
package com.qf.mvc03.exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GlobalException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView("error");
mv.addObject("error",ex.getMessage());
return mv;
}
}
(2). 将实现类注册到 spring 容器中,或是加上 @Component 注解 同时修改包扫描范围
<bean class="com.qf.mvc03.exception.GlobalException"/>
(3). 配置视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
2. 第二种:自己定义类(实际开发中常用的)
(创建 全局异常处理类 )
? @ControllerAdvice “增强的 Controller,它凌驾于普通的 Controller 之上”
? 在类里边去定义各种不同的异常处理方法
(注意修改注解扫描空间)
package com.qf.mvc03.exception;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalException2 {
@ExceptionHandler(ArithmeticException.class)
public String arithmeticException(ArithmeticException e, Model model){
model.addAttribute("error",e.getMessage());
return "error";
}
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Map<String,String> arithmeticException(ArithmeticException e){
Map<String ,String> map = new HashMap<>();
map.put("status", "500");
map.put("message", e.getMessage());
return map;
}
}
3. 第三种:直接在 xml 文件里面配置
SimpleMappingExceptionResolver
(发生什么异常,找什么页面)
其中配置的01表示01.jsp
其中配置的02表示02.jsp
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">01</prop>
<prop key="java.lang.NullPointerException">02</prop>
</props>
</property>
</bean>
<%--
Created by IntelliJ IDEA.
User: lyz
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>01.jsp</h1>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: lyz
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>02.jsp</h1>
</body>
</html>
十、拦截器
作用:抽取 handler 中冗余的功能
1. 自定义拦截器类
package com.qf.mvc03.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
2. 在 spring.xml 中的配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<ref bean="myInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
十一、文件上传
- 两种文件上传方式:新版的不用加依赖,旧版的要加依赖
- 但两种上传方式的接口都是一样的
- 新版的要在 spring.xml 配置 bean,但 bean 内不需要配置属性(它的属性在 web.xml 中进行配置)
- 旧版也要在 spring.xml 配置 bean,同时 bean 内要配置属性
0. 相同的接口类
package com.qf.mvc03.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
@Controller
public class FileUploadController {
private SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/upload")
@ResponseBody
public String uploadFile(MultipartFile file,String username){
System.out.println("username = " + username);
String folderPath = new File("D:\\temp\\img") + sdf.format(new Date());
File folder = new File(folderPath);
if (!folder.exists()){
folder.mkdirs();
}
String oldName = file.getOriginalFilename();
String suffix = oldName.substring(oldName.lastIndexOf("."));
String newName = UUID.randomUUID().toString() + suffix;
try {
file.transferTo(new File(folder,newName));
return "success";
} catch (IOException e) {
e.printStackTrace();
}
return "fail";
}
}
1. 新版文件上传方式
配置上传文件的解析器 StandardServletMultipartResolver
注意,这个地方的配置,必须给 Bean 取名字,且名字必须为 multipartResolver
(1). 在 spring.xml 中配置 bean
<bean class="org.springframework.web.multipart.support.StandardServletMultipartResolver" id="multipartResolver">
</bean>
(2). 在 web.xml 中配置属性
<multipart-config>
<location>D:\temp\temp2</location>
<max-file-size>10000000000</max-file-size>
<max-request-size>10000000000</max-request-size>
<file-size-threshold>10000</file-size-threshold>
</multipart-config>
2. 旧版文件上传方式
(1). 添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
(2). 在 spring.xml 中配置 bean
配置上传文件的解析器 CommonsMultipartResolver
注意,这个地方的配置,必须给 Bean 取名字,且名字必须为 multipartResolver
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="uploadTempDir" value="classpath:/temp"/>
<property name="maxUploadSize" value="10000000000"/>
<property name="maxUploadSizePerFile" value="10000000000"/>
<property name="maxInMemorySize" value="10000"/>
</bean>
十二、文件下载
1. 单读取功能
@GetMapping("/views/{year}/{month}/{day}/{imageName}")
@ResponseBody
public ResponseEntity<byte[]> downloadImg(@PathVariable String imageName, @PathVariable String year,@PathVariable String month,@PathVariable String day) throws IOException {
FileInputStream fis =new FileInputStream("D:\\temp\\img\\"+year+"\\"+month+"\\"+day+"\\"+imageName);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int len=0;
byte[] buf=new byte[1024];
while ((len=fis.read(buf))!=-1){
baos.write(buf,0,len);
}
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.IMAGE_JPEG);
return new ResponseEntity<>(baos.toByteArray(),header, HttpStatus.CREATED);
}
2.1 读取 + 下载( SpringMVC 中的下载)
@GetMapping("/views/{year}/{month}/{day}/{imageName}")
@ResponseBody
public ResponseEntity<byte[]> downloadImg(@PathVariable String imageName, @PathVariable String year,@PathVariable String month,@PathVariable String day) throws IOException {
FileInputStream fis =new FileInputStream("D:\\temp\\img\\"+year+"\\"+month+"\\"+day+"\\"+imageName);
ByteArrayOutputStream baos=new ByteArrayOutputStream();
int len=0;
byte[] buf=new byte[1024];
while ((len=fis.read(buf))!=-1){
baos.write(buf,0,len);
}
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.IMAGE_JPEG);
header.setContentDispositionFormData("attachment",new String(imageName.getBytes("UTF-8"),"ISO-8859-1"));
return new ResponseEntity<>(baos.toByteArray(),header, HttpStatus.CREATED);
}
2.2 读取 + 下载( Servlet 中的下载方式)
@RequestMapping("/{name}")
public void downloadImg(@PathVariable String name, HttpSession session, HttpServletResponse response) throws IOException {
System.out.println("name:"+name);
String path = session.getServletContext().getRealPath("/upload_file");
String real_path = path+"\\"+name;
response.setHeader("content-disposition","attachment;filename="+name);
IOUtils.copy(new FileInputStream(real_path),response.getOutputStream());
}
十三、REST
1. 开发风格
是一种开发风格,遵从此风格开发软件,符合REST风格,则RESTful。
两个核心要求:
- 每个资源都有唯一的标识(URL)
- 不同的行为,使用对应的http-method
访问标识 | 资源 |
---|
http://localhost:8989/xxx/users | 所有用户 | http://localhost:8989/xxx/users/1 | 用户1 | http://localhost:8989/xxx/users/1/orders | 用户1的所有订单 |
请求方式 | 标识 | 意图 |
---|
GET(查询) | http://localhost:8989/xxx/users | 查询所有用户 | POST(添加) | http://localhost:8989/xxx/users | 在所有用户中增加一个 | PUT(更新) | http://localhost:8989/xxx/users | 在所有用户中修改一个 | DELETE(删除) | http://localhost:8989/xxx/users/1 | 删除用户1 | GET | http://localhost:8989/xxx/users/1 | 查询用户1 | GET | http://localhost:8989/xxx/users/1/orders | 查询用户1的所有订单 | POST | http://localhost:8989/xxx/users/1/orders | 在用户1的所有订单中增加一个 |
2. 优点
3. 使用
(1). 定义Rest风格的 Controller
@RequestMapping(value=“/users”,method = RequestMethod.GET)
等价
@GetMapping(“/users”)
@RestController
public class RestController {
@GetMapping("/users")
public List<User> queryAllUsers(){
System.out.println("get");
List<User> users = ....
return users;
}
@PostMapping("/users")
public String addUser(@RequestBody User user){
System.out.println("Post user :"+user);
return "{status:1}";
}
@PutMapping("/users")
public String updateUser(@RequestBody User user){
System.out.println("Put user" user:"+user);
return "{status:1}";
}
@GetMapping("/users/{id}")
public String queryOneUser(@PathVariable Integer id){
System.out.println("Get user id:"+id);
return "{status:1}";
}
@DeleteMapping("/users/{id}")
public String deleteOneUser(@PathVariable Integer id){
System.out.println("delete user id:"+id);
return "{status:1}";
}
}
(2). Ajax请求
<script>
function putUser(){
var xhr = new XMLHttpRequest();
xhr.open("put","${pageContext.request.contextPath}/rest04/users");
xhr.setRequestHeader("content-type","application/json");
var user = {id:1,NAME:"shine",city:"bj","birth":"2020/12/12","salary":100.5};
xhr.send(JSON.stringify(user));
xhr.onreadystatechange=function(){
if(xhr.readyState==4 && xhr.status==200){
var ret = xhr.responseText;
console.log(JSON.parse(ret));
}
}
}
function delUser(){
var xhr = new XMLHttpRequest();
xhr.open("delete","${pageContext.request.contextPath}/rest04/users/1");
xhr.send();
xhr.onreadystatechange=function(){
if(xhr.readyState==4 && xhr.status==200){
var ret = xhr.responseText;
console.log(JSON.parse(ret));
}
}
}
</script>
十四、跨域请求
浏览器对 AJAX 有一定限制:ajax 请求只能发送给当前的网站,不能发给别的网站,就是不能跨域
这话域指的是三个东西一样:一个指的是请求协议(从 htpp ->https 也算跨域),第二个指的是请求域名要一样,第三个端口要一样。这三个东西都要一样就认为你没有跨域,要是这三个有其中一个不一样,就是跨域了。
1. 解决方法
-
允许其他域访问(在被访问方的Controller类上,添加注解) @CrossOrigin("http://localhost:8080")
-
携带对方cookie,使得session可用(在访问方,ajax中添加属性:withCredentials: true) $.ajax({
type: "POST",
url: "http://localhost:8989/web/sys/login",
...,
xhrFields: {
withCredentials: true
}
});
或
var xhr = new XMLHttpRequest();
xhr.withCredentials=true;
···SSM整合
-
传统的:使用 xml 文件去配置 ssm 整合 -
第二种:纯 java 代码去配置 ssm 整合 -
一、传统的(.xml )
1. Spring + SpringMVC
(0). 基本配置
- 打包方式 war
- 配置web修改信息
- 配置Tomcat
(1). 添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.24</version>
</dependency>
(2). 测试 controller
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.hello();
}
}
(3). 测试 service
@Service
public class HelloService {
public String hello() {
return "hello springmvc";
}
}
(4). 配置 spring-servlet.xml
同时注册配置 SpringMVC 注解扫描 以及注解驱动
<context:component-scan base-package="com.qf.xml" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven/>
(5). 配置 applicationContext.xml
通知注册配置 Spring 注解扫描
<context:component-scan base-package="com.qf.xml" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
(6). 再 web.xml 中配置上述两个xml文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2. + MyBatis
(1). 添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.24</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0</version>
</dependency>
(2). 添加数据库配置文件
db.driverClassName=com.mysql.cj.jdbc.Driver
db.username=root
db.password=root
db.url=jdbc:mysql:///mybatis_01?serverTimezone=Asia/Shanghai
db.maxWait=60000
db.initialSize=100
db.maxActive=200
db.minIdle=10
(3). 在 applicationContext.xml 中配置 MyBatis
在 Spring 配置文件中配置 MyBatis 的
- 数据源
- 两个Bean
- sqlSessionFactoryBean
- 接口扫描
<context:property-placeholder location="classpath:db.properties"/>
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="url" value="${db.url}"/>
<property name="maxActive" value="${db.maxActive}"/>
<property name="maxWait" value="${db.maxWait}"/>
<property name="driverClassName" value="${db.driverClassName}"/>
<property name="initialSize" value="${db.initialSize}"/>
<property name="minIdle" value="${db.minIdle}"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.qf.xml.model"/>
<property name="mapperLocations">
<value>
classpath*:com/qf/xml/mapper/*.xml
</value>
</property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
<property name="basePackage" value="com.qf.xml.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
</bean>
(4). 相关 controller、service、mapping、mapping.xml、model
-
controller @RestController
public class UserController {
@Autowired
UserService userService;
@GetMapping("/user")
public List<User> selectAll(){
return userService.selectAll();
}
}
-
service @Service
public class UserService {
@Autowired
UserMapper userMapper;
public List<User> selectAll() {
return userMapper.selectAll();
}
}
-
mapping public interface UserMapper {
List<User> selectAll();
}
-
mapping.xml <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.xml.mapper.UserMapper">
<select id="selectAll" resultType="com.qf.xml.model.User">
select * from `user`;
</select>
</mapper>
-
model public class User {
private Integer uid;
private String uname;
private String upwd;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime udate;
}
(5). 在 pom.xml 配置额外的 resources 资源文件路径
由于本人习惯将 mapping、mapping.xml 放在同一包(dao/mapping)下,所以需要在 pom.xml 额外配置一个 resources 资源文件路径
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
3. 事务配置
- (1). 配置数据源事务管理器
- (2). 配置事务的切面
- (3). 配置事务 AOP
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*"/>
<tx:method name="delete*"/>
<tx:method name="update*"/>
<tx:method name="select*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pc1" expression="execution(* com.qf.xml.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc1"/>
</aop:config>
二、纯 Java 代码
纯 Java 代码进行 SSM 的整合,甚至连 web.xml 都不需要
0. 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qf</groupId>
<artifactId>java_ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.24</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.24</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.14</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.36</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
1. 配置 SpringConfig.java
等效于 applicationContext.xml
- @Configuration //表示这是一个配置类
底层代码剖析,见下方代码块文档注解部分 - @ComponentScan(value = “com.qf.java”,useDefaultFilters = true,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) //扫描特定路径下包的注解,但是不扫描 @Controller 注解
- @PropertySource(“classpath:db.properties”) //表示读取 db.properties
- @EnableTransactionManagement //配置这个注解相当于
<tx:annotation-driven/> - DataSource dataSource() //配置数据源
- SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) //配置Sql会话工厂Bean
- MapperScannerConfigurer mapperScannerConfigurer() //配置映射扫描器配置器
- setEnvironment(Environment environment) // implements EnvironmentAware(Aware的子接口)后重写的方法,用于设置让系统自动调用,给 environment 属性赋值。 目的是用来给 dataSource 数据源的属性注入值/赋值
- TransactionManager transactionManager(DataSource dataSource) //配置事务管理器
package com.qf.java.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
@Configuration
@ComponentScan(value = "com.qf.java",useDefaultFilters = true,excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)})
@PropertySource("classpath:db.properties")
@EnableTransactionManagement
public class SpringConfig implements EnvironmentAware {
private Environment environment;
@Bean
DataSource dataSource(){
DruidDataSource ds =new DruidDataSource();
ds.setUsername(environment.getProperty("db.username"));
ds.setPassword(environment.getProperty("db.password"));
ds.setUrl(environment.getProperty("db.url"));
ds.setDriverClassName(environment.getProperty("db.driverClassName"));
return ds;
}
@Bean
SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setTypeAliasesPackage("com.qf.java.model");
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:com/qf/java/mapper/*.xml"));
return bean;
}
@Bean
MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.qf.java.mapper");
configurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
return configurer;
}
@Override
public void setEnvironment(Environment environment) {
this.environment=environment;
}
@Bean
TransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
}
2. 配置 SpringMVCConfig.java
等效于 spring-servlet.xml
-
@Configuration //表示这是一个配置类 -
@ComponentScan(value = “com.qf.java”,useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)}) //只扫描特定路径下包的 @Controller 注解 -
@EnableWebMvc //配置处理器映射器+处理器适配器;这个配置就类似于 <mvc:annotation-driven/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
(注意此处需要自己继承 HandlerInterceptor 自定义一个拦截器类,重写里面的 preHandle、postHandle、afterCompletion方法)
(我这里的是自定义拦截器类MyInterceptor implements HandlerInterceptor)
-
addCorsMappings(CorsRegistry registry) //这里用于设置跨域请求的 -
configureViewResolvers(ViewResolverRegistry registry) //配置视图解析器 -
configureMessageConverters(List<HttpMessageConverter<?>> converters) //第一种配置 HttpMessageConverter 的方式 -
extendMessageConverters(List<HttpMessageConverter<?>> converters) //第二种配置 HttpMessageConverter 的方式(差别见下方代码块文档注解部分)
package com.qf.java.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.java.interceptor.MyInterceptor;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.*;
import java.text.SimpleDateFormat;
import java.util.List;
@Configuration
@ComponentScan(value = "com.qf.java",useDefaultFilters = false,includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)})
@EnableWebMvc
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**");
}
@Override
public void addCorsMappings(CorsRegistry registry) {
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp().prefix("/WEB-INF/jsp/")
.suffix(".jsp");
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper om = new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
converter.setObjectMapper(om);
converters.add(converter);
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper om = new ObjectMapper();
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
converter.setObjectMapper(om);
converters.add(0,converter);
}
}
3. 配置 WebInit.java
等效于 web.xml
- implements WebApplicationInitializer //继承 WebApplicationInitializer 重写 onStartup(ServletContext servletContext) 方法
(其余内容看代码块)
package com.qf.java.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class WebInit implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.setServletContext(servletContext);
ctx.register(SpringMVCConfig.class,SpringConfig.class);
ctx.refresh();
ServletRegistration.Dynamic springmvc = servletContext.addServlet("springmvc", new DispatcherServlet(ctx));
springmvc.addMapping("/");
}
}
Tips:零碎知识点
1. 静态资源 于 动态资源
- 静态资源:java代码不需要进行任何运算的,就能返回去的这种资源,就叫静态资源
(静态资源就是你想要那种东西,我原封不动的给你返去,我不需要进行任何而外的运行,就是静态资源)
- 动态资源:得运行java代码才能返回、获取、操作的资源叫动态资源
2. 前端页面强制刷新
在浏览器页面:用Ctrl+F5,强制刷新(目的时为了防止前端显示结果用缓存)
3. 前端页面请求状态码为302时
前端页面请求状态码为302时,表示用的时缓存
4. Ant 风格的路径匹配符号
Ant 风格的路径匹配符号
? 可以匹配单个字符
* 可以匹配单个文件名
** 可以匹配多层路径和文件
5. @ResponseBody
表示(在该方法中)我要返回的东西呢,就是这个方法的返回值,不用去查找页面
6. 快速搜索
选定要搜索的内容,点击两下 Shift
7. 查看子类
选定内容,按 Ctrl + H
8. 前端页面错误400
参数转换出错
9. 前端页面错误406
①你想返回的对象,它没法给你转换;
②或者是其实它转换,但是浏览器它识别不出来,不知道返回个啥东西,不知道该如何给你展示出来(浏览器不知道该如何把这个东西展示出来,使用它报406错误)
10. 拦截器和过滤器的区别:
- 执行时机:拦截器晚于过滤器
- 拦截器是一种 AOP 风格的过滤器
过滤器 拦截的是一个请求,请求到服务端之后呢,它可能由某个接口去处理
拦截器 (拦截的力度会更小一些)准确来说拦截器拦截的是处理器,当你去执行某个处理器方法的时候,它给你拦截下来
|