Spring Mvc

家里蹲大学

Spring Mvc

通过把Model,View,Controller分离,把较为复杂的web应用分成逻辑清晰的几部分,是为了简化开发,减少出错

Spring Mvc核心组件

DispatcherServlet:前置控制器、是整个流程控制的核心、控制其他组件的执行、进行统一调度、降低组件之间的耦合性、总指挥
Handler:处理器、完成具体的业务逻辑、相当于 Servlet
HandlerMapping:DispatcherServlet 接收到请求之后、通过 HandlerMapping 将不同的请求映射到不同的 Handler
HandlerInterceptor:处理器拦截器、是一个接口、如果需要完成一些拦截处理、可以实现该接口
HandlerExecutionChain:处理器执行链、包括两部分内容:Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor、如果需要额外设置拦截、可以添加拦截器)
HandlerAdapter:处理器适配器、Handler 执行业务方法之前、需要进行一系列的操作、包括表单数据的验证、数据类型的转换、将表单数据封装到 JavaBean 等、这些操作都是由 HandlerApater 来完成、开发者只需将注意力集中业务逻辑的处理上、DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler
ModelAndView:装载了模型数据和视图信息、作为 Handler 的处理结果、返回给 DispatcherServlet
ViewResolver:视图解析器、DispatcheServlet 通过它将逻辑视图解析为物理视图、最终将渲染结果响应给客户端

Spring Mvc工作流程

1、客户端请求被 DisptacherServlet 接收
2、根据 HandlerMapping 映射到 Handler
3、生成 Handler 和 HandlerIntercepto
、Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一并返回给 DisptacherServlet
4、DispatcherServlet 通过 HandlerAdapter 调用 Handler 的方法完成业务逻辑处理
5、Handler 返回一个 ModelAndView 给 DispatcherServlet
6、DispatcherServlet 将获取的 ModelAndView 对象传给 ViewResolver 视图解析器,将逻辑视图解析为物理视图 View
7、ViewResovler 返回一个 View 给 DispatcherServlet
8、DispatcherServlet 根据 View 进行视图渲染(将模型数据 Model 填充到视图 View 中)
9、DispatcherServlet 将渲染后的结果响应给客户端

springMvc

Spring Mvc使用方法

  • pom.xml
1
2
3
4
5
6
7
8
<dependencies>
<!-- 配置mvc所需依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.11.RELEASE</version>
</dependency>
</dependencies>
  • web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>/</url-pattern>
</servlet-mapping>

</web-app>
  • spring-mvc.xml
1
2
3
4
5
6
7
8
<!--    自动装配-->
<context:component-scan base-package="com.dream.xiaobo"/>

<!-- 配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
  • MyHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
@RequestMapping(value = "/hello")
public class MyHandler {

@RequestMapping(value = "/index",
method = RequestMethod.GET,
params = {"id=1","name=xiaobo", "sex=nan"})
public String index(@RequestParam("id") Integer sId,
@RequestParam("name") String sName,
@RequestParam("sex") String sSex){
System.out.println("控制器执行了");
System.out.println(sId);
System.out.println(sName);
System.out.println(sSex);

return "index";
}

@RequestMapping:将URL请求与业务方法进行映射
@Controller:使其该类成为一个控制器、接受客户端请求、并将该类放入到IOC容器中
value:URL地址值
method:请求类型、get、post、put、delete
params:请求中必须包含的参数、否则无法访问、限制请求参数
@RequestParam:与形参映射、给形参赋值、当形参和params参数相同时可自动赋值、否则需要@RequestParam赋值

  • RESTFUL风格
1
2
3
4
5
6
@RequestMapping(value = "/xiaobo/{id}/{name}", method = RequestMethod.GET)
public String index2(@PathVariable("id") Integer id, @PathVariable("name") String name){
System.out.println(id);
System.out.println(name);
return "index";
}

@ParhVariable:与形参映射、给形参赋值

  • 映射Cookie
1
2
3
4
5
@RequestMapping(value = "/cookie")
public String cookie(@CookieValue(value = "JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
  • 转发
1
2
3
4
@RequestMapping("/forward")
public String forward(){
return "forward:/index.jsp";
}

Spring Mvc默认是转发、所以可以省略

  • 重定向
1
2
3
4
@RequestMapping("/redirect")
public String redirect(){
return "redirect:/index.jsp";
}

Spring Mvc数据绑定

后端直接获取客户端请求中的参数、将参数映射到形参中、数据绑定工作是由HandlerAdapter完成的

  • 普通绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping(value = "/data")
public class MyHandler {

@RequestMapping(value = "jiben")
// @ResponseBody
public String jiben(@RequestParam(value = "num",
required = false,
defaultValue = "0")
String[] name){
String string = Arrays.toString(name);
return string;
}
}

@ResponseBody 表示 Spring MVC 会直接将业务方法的返回值响应给客户端、如果不加 @ResponseBody 注解、Spring MVC 会将业务方法的放回值传递给 DispatcherServlet、再由 DisptacherServlet 调用 ViewResolver 对返回值进行解析、映射到一个 JSP 资源
@RestController:表示该控制器会直接将业务方法的返回值响应给客户端、不进行视图解析
@Controller:表示该控制器的每一个业务方法的返回值都会交给视图解析器进行解析
@RequestParam(value = “num”):将 HTTP 请求中名为 num 的参数赋给形参 id
requried:设置 num 是否为必填项、true 表示必填、false 表示非必填
defaultValue = “0”:如果 HTTP 请求中没有 num 参数、默认值为0

  • List集合绑定

List集合必须进行封装后操作

1
2
3
4
@Data
public class UserList {
private List<User> users;
}
1
2
3
4
5
6
7
8
@RequestMapping("/list")
public String list(UserList userList){
StringBuffer str = new StringBuffer();
for(User user:userList.getUsers()){
str.append(user);
}
return str.toString();
}
  • Map集合绑定
1
2
3
4
@Data
public class UserMap {
private Map<String,User> users;
}
1
2
3
4
5
6
7
8
9
@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();
}
  • JSON绑定
1
2
3
4
5
6
7
<!--    JSON数据转换成Java对象-->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
1
2
3
4
5
<!--  使后缀为.js的放行、不交给dispatcherServlet处理-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
1
2
3
4
5
6
7
8
9
10
<mvc:annotation-driven>
<!-- 消息转换器 -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
</bean>
<!-- 配置fastjson-->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"></bean>
</mvc:message-converters>
</mvc:annotation-driven>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>json页面</title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
$(function () {
var person = {
"id" : 1,
"name" : "xiaobo",
"sex" : "男"
};
$.ajax({
url:"/data/json",
type:"post",
dataType:"JSON",
contentType:"appliaction/json;charset=UTF-8",
data:JSON.stringify(person),
success:function (data) {
alert(data.id + "---" + data.name + "---" + data.sex)
}
})
});
</script>
</head>
<body>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
@RequestMapping(value = "/json", method = RequestMethod.POST)
public Person json(@RequestBody Person person){
System.out.println(person);
person.setId(666);
person.setName("小博");
person.setSex("男");

System.out.println(person);
return person;
}
  • servletAPI
1
2
3
4
5
6
7
8
9
10
11
@RequestMapping(value = "servlet")
public String httpServlet(HttpServletRequest request){

Person person = new Person();
person.setId(1);
person.setName("xiaobo");
person.setSex("男");
request.getSession().setAttribute("person",person);

return "view";
}

Spring Mvc REST

资源表现层状态
URL简洁
有利于不同系统之间资源共享

使用方法

GET用来表示获取资源(select)
POST用来新建资源(insert)
PUT用来表示修改资源(update)
DELETE用来表示删除资源(delete)

1
2
3
4
5
6
7
8
9
10
public interface PersonRepository {

public Collection<Person> findAll();

public Person findById(Integer id);

public void saveOrUpdate(Person person);

public void deleteById(Integer id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Repository
public class PersonRepositoryImpl implements PersonRepository{

private static Map<Integer,Person> map;

static{
map = new HashMap<>();
map.put(1,new Person(1,"xiaobo","男"));
map.put(2,new Person(2,"wyb","男"));
map.put(3,new Person(3,"wangyibo","男"));
}

@Override
public Collection<Person> findAll() {
return map.values();
}

@Override
public Person findById(Integer id) {
return map.get(id);
}

@Override
public void saveOrUpdate(Person person) {
map.put(person.getId(),person);
}

@Override
public void deleteById(Integer id) {
map.remove(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@RestController
@RequestMapping(value = "/reft")
public class ReftController {

@Autowired
private PersonRepositoryImpl personRepository;


@GetMapping(value = "/findAll")
public Collection<Person> findAll(HttpServletResponse response){

response.setContentType("text/json;charset=UTF-8");
return personRepository.findAll();
}

@GetMapping(value = "/findById/{id}")
public Person findById(@PathVariable("id") Integer id,HttpServletResponse response){
response.setContentType("text/json;charset=UTF-8");
return personRepository.findById(id);
}

@PutMapping(value = "/saveOrUpdate")
public void saveOrUpdate(@RequestBody Person person){
personRepository.saveOrUpdate(person);
}

@DeleteMapping(value = "/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
personRepository.deleteById(id);
}
}

文件上传(upload)

  • pom.xml
1
2
3
4
5
6
7
8
9
10
11
<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>
  • upload.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>上传</title>
</head>
<body>
<form action="/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="sc">
<input type="submit" value="提交">
</form>
<img src="${requestScope.path }">
</body>
</html>
  • spring-mvc.xml
1
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
  • uploadController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Controller
@RequestMapping(value = "/file")
public class UploadController {


@PostMapping(value = "/upload")
public String upload(MultipartFile sc, HttpServletRequest request){

if(sc.getSize() > 0){
//获取文件上传保存路径
String path = request.getServletContext().getRealPath("/file");

//获取文件上传名字
String filename = sc.getOriginalFilename();

File file = new File(path,filename);

try {
//读出
sc.transferTo(file);
//放到Request中传送过去
request.setAttribute("path","/file/"+filename);
} catch (IOException e) {
e.printStackTrace();
}
}
return "upload";
}
}

同时上传多个文件

1
2
3
4
5
6
7
8
9
10
11
<body>
<form action="/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="sc">
<input type="file" name="sc">
<input type="file" name="sc">
<input type="submit" value="提交">
</form>
<c:forEach items="${files}" var="file" >
<img src="${file}" width="300px">
</c:forEach>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Controller
@RequestMapping(value = "/file")
public class UploadController {


@PostMapping(value = "/upload")
public String upload(MultipartFile[] sc, HttpServletRequest request){

List<String> list = new ArrayList<>();

for(MultipartFile multipartFile: sc){

if(multipartFile.getSize() > 0){

//获取文件上传保存路径
String path = request.getServletContext().getRealPath("/file");

//获取文件上传名字
String filename = multipartFile.getOriginalFilename();

File file = new File(path,filename);

try {
//读出
multipartFile.transferTo(file);

list.add("/file/" + filename);
//放到Request中传送过去
request.setAttribute("files",list);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "upload";
}
}

文件下载

1
2
3
4
5
<body>
<a href="/file/download/springMvc">springMvc.png</a>
<a href="/file/download/IOC">IOC.png</a>
<a href="/file/download/MVC">MVC.png</a>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Controller
@RequestMapping(value = "/file")
public class DownloadController {

@GetMapping(value = "/download/{name}")
public void download(@PathVariable String name, HttpServletRequest request, HttpServletResponse response){
if(name != null){
name += ".png";
String path = request.getServletContext().getRealPath("file");
File file = new File(path,name);
OutputStream outputStream = null;
if(file.exists()){
response.setContentType("application/forc-download");
response.setHeader("Content-Disposition","attachment;filename="+name);
try {
outputStream = response.getOutputStream();
outputStream.write(FileUtils.readFileToByteArray(file));
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}

Spring MVC 表单标签库

1
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
1
2
3
4
5
6
7
@GetMapping("/get")
public ModelAndView get(){
ModelAndView modelAndView = new ModelAndView("tag");
Student student = new Student(1,"xiaobo",21);
modelAndView.addObject("student",student);
return modelAndView;
}
1
2
3
4
5
6
<form:form modelAttribute="student">
学生ID:<form:input path="id"/><br/>
学生姓名:<form:input path="name"/><br/>
学生年龄:<form:input path="age"/><br/>
<input type="submit" value="提交"/>
</form:form>

Spring Mvc数据校验

  • 基于Validator接口
1
2
3
4
5
6
7
8
9
10
11
12
public class AccountValidator implements Validator {
@Override
public boolean supports(Class<?> aClass) {
return Account.class.equals(aClass);
}

@Override
public void validate(Object o, Errors errors) {
ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
ValidationUtils.rejectIfEmpty(errors,"password",null,"密码不能为空");
}
}
1
2
<bean id="accountValidator" class="com.southwind.validator.AccountValidator"></bean>
<mvc:annotation-driven validator="accountValidator"></mvc:annotation-driven>
  • Annotation JSR - 303校验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- JSR-303 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.6.Final</version>
</dependency>

<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>

<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.3.2.Final</version>
</dependency>
1
<mvc:annotation-driven />
1
2
3
4
5
6
7
8
9
10
11
@Data
public class Person {
@NotEmpty(message = "用户名不能为空")
private String username;
@Size(min = 6,max = 12,message = "密码6-12位")
private String password;
@Email(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\\\.[a-zA-Z0-9-]+)*\\\\.[a-zA-Z0-9]{2,6}$",message = "请输入正确的邮箱格式")
private String email;
@Pattern(regexp = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\\\\\\\d{8}$",message = "请输入正确的电话")
private String phone;
}

@Null 被注解的元素必须为null
@NotNull 被注解的元素不能为null
@Min(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注解的元素必须是一个数字,其值必须小于于等于指定的最大值
@Email 被注解的元素必须是电子邮箱地址
@Pattern 被注解的元素必须符合对应的正则表达式
@Length 被注解的元素的大小必须在指定的范围内
@NotEmpty 被注解的字符串的值必须非空

正确的开始、微小的长进、然后持续、嘿、我是小博、带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:Spring Mvc

文章作者:小博

发布时间:2021年07月06日 - 09:57

最后更新:2021年07月06日 - 10:01

原始链接:https://codexiaobo.github.io/posts/3709047675/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。