SpringMVC总结

1. SpringMVC的执行流程

(1) 首先从客户端接收请求,由DispatchServlet(前端控制器/servlet派遣器)接收

(2) 然后传递给HandlerMapping(映射处理器),HandlerMapping开始通过url寻找对应的处理器(Handler类)

(3) Handler类实例化生成一个具体的handler处理器对象和拦截器(如果有则生成),并封装为一个handlerExecuteChain对象回给DispatchServlet(前端控制器)

(4) DispatchServlet调用HandlerAdapter(Handler适配器),HandlerAdapter调用具体的handler处理器对象(中的方法),handler执行完封装为一个modleAndView返回给DispatchServlet

(5) DispatchServlet再将view(逻辑视图)交给ViewResolver(视图解析器)进行解析,返回具体的view(物理视图)

(6) DispatchServlet将view进行model(数据)填充,最终响应用户

在这里插入图片描述

2. SpringMVC配置

使用springMVC必须配置的三大件

处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)

只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可

在resource目录下添加springmvc.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: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">

   <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
   <context:component-scan base-package="nuc.ss.controller"/>
   <!-- 让Spring MVC不处理静态资源 -->
   <mvc:default-servlet-handler />
   <!--
   支持mvc注解驱动
       在spring中一般采用@RequestMapping注解来完成映射关系
       要想使@RequestMapping注解生效
       必须向上下文中注册DefaultAnnotationHandlerMapping
       和一个AnnotationMethodHandlerAdapter实例
       这两个实例分别在类级别和方法级别处理。
       而annotation-driven配置帮助我们自动完成上述两个实例的注入。
    -->
   <mvc:annotation-driven />

   <!-- 视图解析器 -->
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
         id="internalResourceViewResolver">
       <!-- 前缀 -->
       <property name="prefix" value="/WEB-INF/jsp/" />
       <!-- 后缀 -->
       <property name="suffix" value=".jsp" />
   </bean>

</beans>

3. SpringMVC常用注解

(1) @Controller

@Controller 在类定义处添加,使其成为⼀个控制器(也可以称为Handler),用于接收客户端请求

(2) @RequestMapping

@RequestMapping可以在类,也可以在方法前添加,用于将 URL 请求与业务方法进行映射,也就是让HandlerMapping(映射处理器)能找到处理的业务方法

@RequestMapping注解的参数说明

① value

指定 URL 请求的实际地址

② method

指定请求类型,GET、POST、PUT、DELET,不写则代表都可以接收

③ params

指定请求中必须包含某些参数,否则无法调用该方法

例如以下代码

@RequestMapping(value = "/index",params = {"name","id=123"})
public String toIndex(){
 return "index"; }

上述代码表示请求中必须包含 name 和 id 两个参数,同时 id 的值必须是123

参数绑定:

在形参列中通过添加 @RequestParam 注解完成 HTTP 请求参数与业务方法形参的映射
如果不写@RequestParam,那么形参名需要和HTTP请求参数一一对应,如果不对应,则形参会赋予null值

required = true 表示必须要传递参数 defaultValue可以写默认值

@RequestMapping(value = "/index",params = {"name","id=10"})
public String toIndex(@RequestParam("name") String userName,@RequestParam("id",required = false,defaultValue = "123") int userId){
 System.out.println(userName);
 System.out.println(userId);
 return "index"; 
 }

上述代码中,业务方法将请求的参数 name 和 id 分别赋给了形参 userName 和 userId ,同时⾃动完成了数据类型转换,这些工作是由HandlerAdapter(handler适配器)完成的

如果形参是类,HandlerAdapter还能将请求的参数封装成该类对象并赋值

注意:基本类型不能赋予null值,如果不对应且参数类型是基本数据类型则会报错,解决方法:使用包装类

restful 风格的URL参数接收写法:

@RequestMapping("/rest/{name}/{id}")
public String rest(@PathVariable("name") String userName,@PathVariable("id") userId){
 System.out.println(userName);
 System.out.println(userId);
 return "index"; 
 }

(3) @ResponseBody

ResponseBody作用于方法上,代表返回客户端一个json字符串,否则默认是返回给DispatchServlet (servlet派遣器)然后再传递给ViewResolver(视图解析器),也可以看作ResponseBody返回的是Model,不加该注释默认是返回ModelAndView

(4) @RestController

@RestController作用于类上,相当于该类所有方法都标记上了@ResponseBody

补充:什么时候使用@Controller,什么时候使用@RestController?

如果Handler只是纯粹给外提供数据返回服务,则可以选用@RestController,但如果是作为一个完整的后端响应服务,则选用@Controller

4. SpringMVC数据绑定的方式

我们可以将要接收的数据分为几种类型来说明:基本数据类型、实体类、数组、List集合、Map集合、Json

业务方法中的形参会由HandlerAdapter自动去获取

① 基本数据类型

基本数据类型,直接在方法形参中写出即可

② 实体类

实体类需要形参配对(例如input标签的name属性需要和实体类的属性名对应),HandlerAdapter会自动进行封装,对在上一标题内容已经说明

@Data
public class User {
    String name;
    Integer id;
}
<form action="/save" method="post">
    ⽤户id:<input type="text" name="id"/><br/>
    ⽤户名:<input type="text" name="name"/><br/>
    <input type="submit" value="注册"/>
</form>
@RequestMapping(value = "/hello/save",method = RequestMethod.POST)
    public String login(User user){
        return "index";
    }

② Array

对于数组,直接在形参中用数组的写法接收

 @RequestMapping("/array")
 public String array(String[] name){
 String str = Arrays.toString(name);
 return "index";
}

③ List

Spring MVC 不⽀持 List 类型的直接转换,需要对 List 集合进⾏包装(因为前端参数只能给对象的属性赋值,不能直接给对象赋值)

@Data
public class UserList {
    private List<User> users;
}

页面表单提交写法

<form action="/data/list" method="post">
	 ⽤户1编号:<input type="text" name="users[0].id"/><br/>
	 ⽤户1名称:<input type="text" name="users[0].name"/><br/>
	 ⽤户2编号:<input type="text" name="users[1].id"/><br/>
	 ⽤户2名称:<input type="text" name="users[1].name"/><br/>
	 ⽤户3编号:<input type="text" name="users[2].id"/><br/>
	 ⽤户3名称:<input type="text" name="users[2].name"/><br/>
	 <input type="submit" value="提交"/>
 </form>

对应业务方法

@RequestMapping("/list")
public String list(UserList userList){
	 StringBuffer str = new StringBuffer();
	 for(User user:userList.getUsers()){
	 str.append(user.toString());
	 }
 return "index";
}

方法说明:将前端传来的List集合参数作为某个对象的属性来完成赋值

这里即是通过包装类UserList,将List<User>作为UserList的属性以赋值(使用StringBuffer是为了提高效率)

④ Map

Map也需要包装类的方法来完成数据绑定,原理和接收List集合类似

包装类

@Data
public class UserMap {
 private Map<String,User> users; }
<body>
 <form action="/data/map" method="post">
 ⽤户1编号:<input type="text" name="users['a'].id"/><br/>
 ⽤户1名称:<input type="text" name="users['a'].name"/><br/>
 ⽤户2编号:<input type="text" name="users['b'].id"/><br/>
 ⽤户2名称:<input type="text" name="users['b'].name"/><br/>
 ⽤户3编号:<input type="text" name="users['c'].id"/><br/>
 ⽤户3名称:<input type="text" name="users['c'].name"/><br/>
 <input type="submit" value="提交"/>
 </form>
</body>

这里的key键可以随便写,但是不要重名

业务方法

@RequestMapping("/map")
public String map(UserMap userMap){
 StringBuffer str = new StringBuffer();
 for(String key:userMap.getUsers().keySet()){
 User user = userMap.getUsers().get(key);
 str.append(user);
 }
 return str.toString();
}

方法说明:通过keySet()方法获得key的集合,然后遍历key,用实体类的实例使用get(Key)方法取出对象以完成赋值

⑤ Json

Spring MVC 中的 JSON 和 JavaBean 的转换需要借助于 fastjson,在pom.xml 引⼊相关依赖

<!-- 配置fastjson -->
 <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
 <script type="text/javascript">
	 $(function(){
		 var user = {
		 "id":123,
		 "name":"小明"
	 };
	 $.ajax({
		 url:"/json",
		 data:JSON.stringify(user),
		 type:"POST",
		 contentType:"application/json;charset=UTF-8",
		 dataType:"JSON",
		 success:function(data){
		 alter(data.id+" "+data.name);
		 }
     })
     });
 </script>
@RequestMapping("/json")
public User json(@RequestBody User user){
 System.out.println(user);
 return "index"; 
 }

5. SpringMVC 数据模型解析(添加模型数据)

几种常见的添加模型数据方式:

① Map
② Model
③ ModelAndView
④ @ModelAttribute
⑤ @SessionAttribute

前四种都是将数据添加到Request ,⑤是添加到session

(1) Map

通过Map存入一组键值对,同时会将其也存入Request中,在前端页面直接从Request中去获取数据,也就是等同于直接使用request.addAttribute(“user”,user)

业务方法

@RequestMapping("/map")
public String map(Map<String,User> map){
 User user = new User();
 user.setId(123);
 user.setName("小明");
 map.put("user",user);
 return "view";
  }

前面取得数据的方式(el表达式)

<body>
 ${requestScope.user}
</body>

(2) Model

@RequestMapping("/model")
public String model(Model model){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 model.addAttribute("user",user);
 return "view"; 
 }

(3) ModelAndView

使用ModelAndView有多钟添加数据的方式,原理都是通过构造函数传参的不同去添加,这里列出3个例子

@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 ModelAndView modelAndView = new ModelAndView();
	 modelAndView.addObject("user",user);
	 modelAndView.setViewName("view");
 	 return modelAndView;
 }
@RequestMapping("/modelAndView2")
public ModelAndView modelAndView2(){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 ModelAndView modelAndView = new ModelAndView();
	 modelAndView.addObject("user",user);
	 View view = new InternalResourceView("/view.jsp");
	 modelAndView.setView(view);
	 return modelAndView; 
 }
@RequestMapping("/modelAndView3")
public ModelAndView modelAndView3(){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 ModelAndView modelAndView = new ModelAndView("view");
	 modelAndView.addObject("user",user);
	 return modelAndView; 
 }

(4) HttpServletRequest

原生的Servlet的Request添加方式

@RequestMapping("/request")
public String request(HttpServletRequest request){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 request.setAttribute("user",user);
	 return "view"; 
 }

(5) @ModelAttribute注解

@ModelAttribute 注解用于添加在方法上,说明该方法专门用来返回要填充到模型数据中的对象,添加了该注解的方法总是会先于业务方法先执行(执行任意一个业务方法前都会先执行该方法再执行)

不使用return也可以使用Map或者Model来添加数据

@ModelAttribute
public User getUser(){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 return user;
  }

使用了该注解后,业务方法不需要再去添加该方法已添加的数据

@RequestMapping("/modelAttribute")
public String modelAttribute(){
 return "view";
}

(6) 将数据添加到session中

① 在业务方法中添加到session

session是从request中得到的

@RequestMapping("/session")
public String session(HttpServletRequest request){
	 HttpSession session = request.getSession();
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 session.setAttribute("user",user);
	 return "view"; 
 }

获取session这一步可以直接交给HandlerAdapter去做,即可以直接在形参中写出

@RequestMapping("/session2")
public String session(HttpSession session){
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 session.setAttribute("user",user);
	 return "view"; 
 }

② 使用@SessionAttribute注解(一般不常用)

@SessionAttribute注解用于添加在类上,表示该类所业务方法执行时,都会对应去查找@SessionAttribute中的value值,如果request.setAttribute中的key值和value值中的key对应,那么会直接添加到对应session中

例如

@SessionAttributes(value = {"user","address"})
public class ViewHandler {
}

那么该类的业务方法中只要向 request 中添加了 key = “user”、key = “address” 的对象时,SpringMVC 会⾃动将该数据添加到 session 中

(7) 将数据添加到Application中

@RequestMapping("/application")
public String application(HttpServletRequest request){
	 ServletContext application = request.getServletContext();
	 User user = new User();
	 user.setId(123);
	 user.setName("小明");
	 application.setAttribute("user",user);
	 return "view"; 
 }

备注:使用HttpServletRequest或session都是使用了servlet原生api的方式

6. 自定义数据转换器

数据转换是指将客户端 HTTP 请求中的参数转换为业务方法中定义的形参

HandlerApdter 已经提供了部分转换,String 转 int,String 转 double,表单数据的封装(成实体类)等

但是在特殊的业务场景下,HandlerAdapter ⽆法进进转换,就需要自定义转换器

以客户端传入String类型,但是需要转换成Date类型为例

① 创建DateConverter类,继承Converter接口,实现convert方法,即代表它是一个转换器

public class DateConverter implements Converter<String, Date> {
	 private String data;
	 public DateConverter(String data){
	 this.data = data;
	 }
	 @Override
	 public Date convert(String str) {
	 SimpleDateFormat simpleDateFormat = new
	 SimpleDateFormat(this.data);
	 Date date = null;
	 try {
	 date = simpleDateFormat.parse(str);
	 } catch (ParseException e) {
	 e.printStackTrace();
	 }
	 return date;
	 }
}

② 在xml中配置自定义转换器

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	 <property name="converters">
		 <list>
			 <bean class="com.ruoxi.converter.DateConverter">
				<constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
			 </bean>
		 </list>
	 </property>
</bean>

在mvc驱动中注册转换器

<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

③ 表单提交

<body>
 <form action="/converter/date" method="post">
 请输⼊⽇期:<input type="text" name="date"/>(yyyy-MM-dd)<br/>
 <input type="submit" value="提交"/>
 </form>
</body>

④ 业务方法

@ResponBody
@RequestMapping("/date")
 public String date(Date date){
 return date.toString();
 }

7. 文件上传与下载

Spring MVC 对 Apache fileupload 组件这种上传方式进⾏了封装

(1) 配置

① 在pom.xml中添加依赖

 <dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.5</version>
</dependency> 
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.3</version>
</dependency>

② web.xml 中防止过滤静态文件 即以默认的方式去处理不交给servletMapping(这里以.png为例)
(静态资源都需要这么做 在标题2中的xml已经完成,单独设置的话需要以下这么做)

<servlet-mapping>
 <servlet-name>default</servlet-name>
 <url-pattern>*.png</url-pattern>
</servlet-mapping>

③ springmvc.xml 配置上传组件 (resouces中的xml)

<!-- 配置上传组件 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>

(2) 单文件上传

1、input 的 type 设置为 file
2、form 的 method 设置为 post(get 请求只能将文件名传给服务器)
3、form 的 enctype 设置为 multipart-form-data(如果不设置只能将⽂件名传给服务器)

<body>
 <form action="/file/upload" method="post" enctype="multipart/form-data">
 <input type="file" name="img"/>
 <input type="submit" value="上传"/>
 </form>
 <img src="${path}">
</body>

文件上传原理是调用输入输出流,SpringMVC对其进行了封装,可以直接调用transferTo(File)函数

request.setAttribute(“path”,"/file/"+name)可以保存文件的路径,通过这种方式,前端可以使用${}el表达式取得文件在页面上展示

@PostMapping("/upload")
 public String upload(MultipartFile img, HttpServletRequest request){
	 if(img.getSize()>0){
	 //获取保存上传⽂件的file路径 (这里默认是在tomcat文件夹里)
		 String path = request.getServletContext().getRealPath("file");
		 //获取上传的⽂件名
		 String name = img.getOriginalFilename();
		 //根据file路径创建一个空的名字为name的文件
		 File file = new File(path,name); 
		 try {
		 //将MultipartFile img文件赋予给file
		 img.transferTo(file);
		 //保存上传之后的⽂件路径
		 request.setAttribute("path","/file/"+name);
		 } catch (IOException e) {
		 e.printStackTrace();
		 }
	 }
	 return "upload";
 }

SpringMVC中如何实现转发和重定向,有什么区别?

转发到页面return"forward:+绝对地址"。转发到控制器其他方法:return的是"forward:+类上requestmapping的地址+方法上requestmapping的地址"

重定向到页面:return的是"redirect:+绝对地址",注意不能重定向访问WEB-INF下的资源。重定向到控制器其他方法:return的是"redirect:+类上requestmapping的地址+方法上requestmapping的地址"。重定向到外部链接:return的是"redirect:+链接地址

转发和重定向的区别是转发只是一次请求重定向是两次请求转发地址栏不变,重定向地址栏将改变转发只能到内部资源,重定向可以到内部或外部资源;转发可以到WEB-INF下资源,重定向不可以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值