SpringMVC
一、项目配置
1.web.xml配置
首先再web.xml中配置SpringMvc的前端控制器DispatcherServlet,对浏览器发送的请求进行统一处理
<servlet>
<!-- 配置DispatcherServlet -->
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定spring mvc配置文件位置 不指定使用默认情况 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-mvc.xml</param-value>
</init-param>
<!-- 设置启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ServLet 匹配映射 -->
<servlet-mapping>
<!-- 要与上面的servlet-name一致 -->
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2. springmvc.xm配置
扫描包中的的组件,并配置thymeleaf视图解析器
<!-- 扫描组件 -->
<context:component-scan base-package="com.zzx.mvc"></context:component-scan>
<!-- 开启mvc注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- thymeleaf视图解析器-->
<!-- 配置视图解析器-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"></property>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
总结:
二、基本注解
@RequestMapping
当浏览器发送请求到服务器,再通过DisPatcherServlet接收到请求之后,将请求地址和控制器方法所使用的注解@RequestMapping的value属性值进行匹配,如果能匹配成功当前的方法就是处理请求的方法,而再这个方法里返回的字符串配成为试图名称,再又试图解析器进行解析,并加上视图前缀和视图后缀找到相对应的html文件,最后再通过thymeleaf解析之后响应到浏览器。
1. @RequestMapping在方法上的话 value值是唯一的
@RequestMapping的位置 可以在类上也可以在方法名上
//这样浏览器匹配的请求就为 localhost:8080/zhixun/index/test
//在使用@RequestMapping时 必须要填写value值 否则会异常 报错 404
@Controller
@RequestMapping("/zhixun")
public class T{
@RequestMapping("/index")
public String index(){
return "test";
}
// 源码 String[] value
// 说明可以用多个不相同的请求 使用一个方法
@RequestMapping(
value = {"index1","index2"}
)
public String index(){
return "test";
}
}
2. @RequestMapping的method属性
@RequestMapping的method属性通过请求方式(get / post)匹配请求映射
get: 在请求时,参数会拼接在请求地址后面,以问号进行拼接后面为&请求参数名=请求参数值,类似于(localhost:8080/index?id=1),get的参数是有限的,相比之下post的参数相当于无限。在文件上传中,是无法使用get请求的,因为是文件所以无法进行拼接,只会拼接文件名。
post: 在请求时不会将参数进行拼接,而是将参数放在请求体中,但在请求体中格式依然跟get一样name=value&name=value 。但是相比之下post请求比get请求更为安全。既然get不安全,所以在传输中get请求是比post请求速度快的,因为它是伴随着请求地址传过去的。
在form表单中 method只有get/post 如果想使用put/delete 需要导入RESTful API。
@Controller
@RequestMapping("/zhixun")
public class T{
// 源码 String[] value
// 说明可以用多个不相同的请求 使用一个方法
@RequestMapping(
value = {"index1","index2"},
// 源码 String[] method
//当满足value属性 缺不满足method属性 浏览器报错405错误,错误信息:Request method 'POST' not supported
//在不写method属性的话 任何请求都允许匹配
method = {"RequestMapping.GET,RequestMapping.POST"}
)
public String index(){
return "test";
}
}
- PUT 请求:
PUT
请求用于向服务器发送数据,以更新或创建资源。- 它通常用于更新指定的资源,客户端需要提供完整的资源表示,包括要更新的信息以及资源的标识。
- 如果服务器已经有了指定标识的资源,
PUT
请求会用新的数据替代旧的数据。 - 如果服务器没有指定标识的资源,
PUT
请求会创建一个新的资源。 PUT
请求是幂等的,多次调用相同的PUT
请求应该产生相同的结果。
- DELETE 请求:
DELETE
请求用于请求服务器删除指定的资源。- 它通常用于删除不再需要的资源,客户端需要提供要删除资源的标识。
- 当服务器接收到
DELETE
请求时,它应该删除指定标识的资源,并返回成功的响应。 DELETE
请求也是幂等的,多次调用相同的DELETE
请求应该产生相同的结果。
需要注意的是,PUT
和 DELETE
请求不像 GET
和 POST
请求那样常见,通常用于特定的RESTful API或需要资源更新和删除的Web应用程序。此外,对于 DELETE
请求,需要谨慎使用,因为它会永久删除资源,可能导致数据丢失。在使用这些请求时,应该仔细考虑安全性和业务逻辑。
3. @RequestMapping的Params属性
@RequestMapping的params属性通过请求的请求参数匹配请求映射
@Controller
@RequestMapping("/zhixun")
public class T{
// 源码 String[] value
// 说明可以用多个不相同的请求 使用一个方法
@RequestMapping(
value = {"index1","index2"},
// 源码 String[] method
//当满足value属性 缺不满足method属性 浏览器报错405错误,错误信息:Request method 'POST' not supported
//在不写method属性的话 任何请求都允许匹配
method = {"RequestMapping.GET,RequestMapping.POST"}
// 源码 String params
//加了params属性就好比 localhost:8080/index?后面必须得有username这个属性且必须等于admin 否则匹配不上这个方法
//如果是!username 那就是不能有username这个属性。
//如果是!username=admin,那就是username属性必须不能等于admin 否则匹配不上
//匹配不成功 报错信息 400
params = {"username=admin"}
)
public String index(){
return "test";
}
}
thymeleaf测试
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<!-- 传Params的值 -->
<!-- localhost:8080/index?username=admin&password=123 -->
<a th:href="@{/index(username='admin',password='123')}"></span>
</body>
</html>
4. @RequestMapping的headers属性
@RequestMapping的params属性通过请求的请求头信息匹配请求映射 匹配不成功报错 404
5. @RequestMapping支持ant风格格式
?: 表示任意的当个字符
*: 表示任意的0个或者多个字符
**: 表示任意一层或者多层目录
注意: 在使用**时,只能使用/**/XXX的方式
@Controller
@RequestMapping("/zhixun")
public class T{
// localhost:8080/a[任意的单个字符]a/test
@RequestMapping(“/a?a/testAnt")
public String index(){
return "test";
}
}
6. SpringMVC支持路径中的占位符(重点!!)
原始方式: /delete?id=1
rest方式: /delete/1
SpringMVC路径中的占位符常用于result风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符(xxx)表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参。
<a th:href="@{/zhixun/index/1/admin}">测试路径中的占位符</a>
@Controller
@RequestMapping("/zhixun")
public class T{
// localhost:8080/a[任意的单个字符]a/test
@RequestMapping(“/index/{id}/{username}")
public String index(@PathVariable("id") Integer id,@PathVariable("username") String username){
return "test";
}
}
三、SpringMVC获取请求参数
1. 通过servletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文对象
@Controller
@RequestMapping("/zhixun")
public class T{
// localhost:8080/a[任意的单个字符]a/test
@RequestMapping(“/index")
public String index(HttpServletRequest request){
String username = request.getParameter("username");
String pwd = request.getParameter("pwd");
return "test";
}
}
2. 通过形参名字与请求名字一致
<a th:href="@{/zhixun/index(username = 'admin',password = '123')}">测试路径中的占位符</a>
当形参的名称和请求里的名称一样,可以直接获取
@Controller
@RequestMapping("/zhixun")
public class T{
@RequestMapping(“/index")
// 如果获取的类型是数组(相同的名字却有多个值)可以通过数组,
// 也可以通过String类型获取,如果是String类型的话,SpringMVC会自动用逗号隔开
public String index(String username,String password){
System.out.println("username" + username + ", " + "password" + password);
return "test";
}
}
3. 通过@RequestParams
当请求里的参数与方法中的形参不相同时,就无法使用第二种方法进行参数获取,此时我们可以使用@RequestParams注解将请求参数与方法中的形参进行绑定,从而获取到参数值。
@Controller
@RequestMapping("/zhixun")
public class T{
@RequestMapping(“/index")
// 将请求参数和形参进行绑定
public String index(
// @RequestParams(value = "user_name",required = false)默认为true 必须传输
// 就是说 当为false的时候不传user_name这个参数也可以正常运行
// 也可以加一个defaultValue 当不传输时 会有一个默认值
/// @RequestParams(value = "user_name",required = false,defaultValue="zhixun")
@RequestParams("user_name") String username,
@RequestParams("pwd") String password
){
System.out.println("username" + username + ", " + "password" + password);
return "test";
}
}
4. 通过@RequestHeader
5. 通过@CookieValue
Session依赖于Cookie,Cookie是客户端的会话技术而session是服务端的会话技术。每当调用getsession方法的时候,就会创建一个key为JSessionID。
当第一次使用getSession方法时,Cookie会存在当前的响应报文中,因为在第一次进行getSession方法的时候,会先检测一下请求报文中是否含有JSessionID的Cookie,如果没有就说明此次会话中第一次创建session对象。创建好的Cookie会存放在服务器中的Map集合,并创建一个key为JSessionID,值为随机序列的Map对象。还会将HttpSession对象存储到服务器维护的Map集合中,以及Cookie的值作Map集合的key,把session对象作为Map集合的值进行存储。最后在把cookie响应到浏览器。
6. 通过POJO获取请求参数
可以在控制方法中的形参位置写一个实体对象,此时若浏览器传输的请求参数的名称和实体类中的属性名一致,就会自动为此属性赋值
<form th:action="@{/index}" method = "post">
用户名:<input type = "text" name="username"/>
密 码:<input type = "text" name="pwd"/>
<button type="submit"></button>
</form>
@Controller
public class T{
@RequestMapping(“/index")
// User -> username,pwd
public String index(User user){
System.out.println("username" + user.getUserName() + ", " + "password" + user.getPwd());
return "test";
}
}
7. 乱码处理
get请求导致的乱码,需要去tomcat中修改
找到tomcat的安装路径下的config/server.xml文件
post请求导致的乱码,需要在web.xml中配置filter属性
四、域对象共享数据
application(当前服务器) > session(当前浏览器) > request(当前会话)
在session中有一个机制,钝化/活化
钝化:当我们服务器关闭了,浏览器没关闭说明会话在继续,我们存储在session中的数据会经过序列化到磁盘上。
活化:如果浏览器仍然没有关闭,但是服务器又重新开启了。它就会将钝化文件的内容重新读取到session中。
所以session中的数据跟服务器关闭没有关系,只跟浏览器关闭有关系。
1. 属于ServletAPI向request域对象共享数据
@RequestMapping("/index")
public String test(HttpServletRequest request){
request.setAttribute("test","hhhh");
return "index";
}
2. 使用ModelAndView向request域对象共享数据
@ReqestMapping("/index")
public ModelAndView test(){
/*
* ModeAndView又model和View功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
// 向请求域共享数据
mav.addObject("testScope","hello,ModelAndView");
//设置视图,实现页面跳转
mav.setViewName("success");
return mav;
}
3. 使用形参的方式向request域对象共享数据
@ReqestMapping("/index")
public String test(Model model){
/*
* 用形参的方式,就不需要设置视图
*/
// 向请求域共享数据
mav.addObject("testScope","hello,ModelAndView");
return "success";
}
4. 使用map向request域对象共享数据
@ReqestMapping("/index")
public String test(Map<String,Object> map){
/*
* 用形参的方式,就不需要设置视图
*/
// 向请求域共享数据
map.put("testScope","hello,ModelAndView");
return "success";
}
5. 使用ModelMap向request域对象共享数据
@ReqestMapping("/index")
public String test(ModelMap modelMap){
// 向请求域共享数据
map.put("testScope","hello,ModelAndView");
return "success";
}
6. Map/Model/ModelMap 底层实现
它们在向request域对象共享数据,都是通过BindingAwareModelMap实现的
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
7. 向Session域中共享数据
- 第一种通过原生servletAPI的方式
@ReqestMapping("/testSession")
public String test(HttpSession session){
// 向请求域共享数据
session.setAttribute("testSessionScope","hhhh");
return "success";
}
<p th:text="${session.testSessionScope}" />
- 通过@SessionAttributes注解
方式一:通过注解的value属性:
@Controller
@SessionAttributes("user") //将ModelMap中key为user的属性共享到session中
public class DemoController {
@RequestMapping("/hello")
public String hello(ModelMap model) {
//向ModelMap中添加key为user和user1的属性
model.addAttribute("user", new User("zhixun", "hhhh"));
return "result";
}
}
方式二:通过注解的types属性:
@SessionAttributes(types = {User.class})
@Controller
public class DemoController{
@RequestMapping("/hello")
public String hello(Map<String, Object> map){
map.put("user", new User("zhixun", "hhhh"));
return "hello";
}
}
8. 向application域中共享数据
@ReqestMapping("/testApplication")
public String test(HttpSession session){
// 创建ServletContext对象
ServletSession application = session.getServletContext();
application.setAttribute("testSessionScope","hhhh");
return "success";
}
五、SpringMVC视图
1. ThymeleafView
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和后缀所得到最终路径,会通过转发的方式实现跳转。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
2. InternalResourceView 转发视图
@ReqestMapping("/testApplication")
public String test(HttpSession session){
// 创建ServletContext对象
ServletSession application = session.getServletContext();
application.setAttribute("testSessionScope","hhhh");
return "success";
}
@ReqestMapping("/index")
public String test(HttpSession session){
// 通过forward进行转发资源
return "forward:/testApplication";
}
3. 重定向视图
转发和重定向的区别:
转发:浏览器发送一次请求,转发是发送服务器内部的跳转,所以请求还是浏览器第一次的请求。转发可以获取请求域中的数据,重定向不可以。转发能访问WEB-INF中的请求,重定向不可以。转发不能跨越,重定向可以。因为转发是发送在服务器内部的,它只能访问服务器内部的资源,而重定向是浏览器发送的两次请求,浏览器可以访问任何资源。
重定向:浏览器发送了两次请求,第一次访问servlet,第二次访问重定向的请求。最终地址为重定向的地址。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
4. 视图控制器view-controller
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示。
<!--
在Spring-mvc.xml中配置
path: 设置处理的请求地址
view-name: 设置请求地址所对应的视图名称
-->
<!-- !!注意 如果在spring-mvc.xml中配置了 view-controller会导致 Controller类里面配置所有映射将全部失效-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>
<!-- !!必须添加,才能保证不失效 -->
<mvc:annotation-driven />
六、 RESTFul
1. RESTFul简介
2. RESTFul的实现
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
3. put请求
若想发送put请求,需要在web.xml文件中配置HiddenHttpMethodFilter过滤器
<!-- 一定要放在在 编码配置后面 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
七、 HttpMessageConverter
HttpMessageConverter,报文信息转换器,将请求报文转换为java对象,或将java对象转换为响应报文。HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity。
@RequestBody: 将请求报文转换为java对象。
@ResponseBody: 将java对象转换为响应体。
RequestEntity: 请求实体,可以接收整个请求报文(既可以接收请求头,也能接收请求体)。
ResponseEntity: 可将此对象转换为响应报文。
1. @RequestBody
@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值。
<form th:action="@{/testRequestBody}" method="post">
用户名:<input type = "text" name = "username"><br>
密码:<input type = "password" name = "password"><br>
<input type="submit"/>
</form>
@ReqestMapping("/test")
//@ResponseBody 将请求报文转换为java对象
public String test(@ResponseBody String requestBody){
System.out.println("requestBody:" + requestBody);
return "success";
}
//输出结果
requestBody:username=admin&password=123
2. RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息
@ReqestMapping("/test")
//@ResponseBody 将请求报文转换为java对象
public String test(RequestEntity<String> requestEntity){
//requestEntity表示整个请求报文的信息
System.out.println("requestHeader:" + requestEntity.getHeaders());
System.out.println("requestBody:" + requestEntity.getBody());
return "success";
}
//输出结果
requestBody:username=admin&password=123
3. @ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
@ReqestMapping("/test")
//@ResponseBody 将请求报文转换为java对象
//放回的值就是页面显示的数据
public String test(RequestEntity<String> requestEntity){
return "success";
}
4. SpringMvc处理json
@ReqestMapping("/test")
//@ResponseBody
//返回的是user对象 直接返回会报500错误 需要转为json格式
public User test(RequestEntity<String> requestEntity){
return "success";
}
需要加入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
实体类转json为json对象 list转json为json 数组
5. 处理ajax
请求超链接
通过vue和axios处理点击事件
6. @RestController注解
@RestController注解是springMvc提供的一个复合注解,标识在控制器类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponeseBody注解
7. @ResponseEntity
ResponseEntity用于控制器方法的返回值,该控制器方法的返回值就是响应到浏览器的响应报文。
器方法的返回值,该控制器方法的返回值就是响应到浏览器的响应报文。
八、文件上传和下载
1.文件下载
使用ResponseEntity实现下载文件的功能
文件下载:从服务器将文件给下载到客户端/浏览器端
文件上传: 从浏览器端上传到服务器端,但是不管是下载还是上传,底层都是文件赋值。
文件下载:
文件上传:
-
添加上传jar依赖
-
配置文件解释器
-
@RequestMapping("/testUp") //一定要配置文件解析器 通过id来进行匹配 //不配置 就无法接收MultipartFile这种类型 //因没有文件服务器,所有只能传输到tomcat服务器,获取服务器需要session public String testUp(MultipartFile photo,HttpSession seesion) throws IOException{ //获取上传文件的文件名 String fileName = photo.getOriginalFilename(); //获取上传的文件的后缀名 String suffixName = fileName.subString(fileName.lastIndexof(".")); //将UUID作为文件名 防止相同名字文件互相覆盖 String uuid = UUID.randomUUID().toString(); //将UUID和后缀名拼接,做为最终的文件名 fileName = uuid + suffixName; //通过ServletContext获取服务器中photo目录的路径 ServletContext context = session.getServletContext(); String photoPath = context.getRealPath("photo"); File file = new File(photoPath); //判断photoPath路径是否存在 if(!file.exists()){ //若不存在,创建目录 file.mkdir(); } String finalPath = photoPath + File.separator + fileName; //资源转移 photo.transfetTo(new File(finalPath)); }
九、拦截器
1. 拦截器的配置
public class FirstInterceptor implements HandlerInterceptor{
//重写三种方法
//controller方法之前执行
public boolean preHandle(){}
//controller方法之后执行
public void postHandle(){}
//视图渲染之后执行
public void afterCompletion(){}
}