0%

【SpringMVC】细节整理

关于SpringMVC框架的细节介绍

一、Controller配置总结

1.1 Controller介绍

  • Controller:控制器
  • 控制器提供访问应用程序的行为,可以通过实现接口/注解的形式来实现
  • 控制器负责解析用户的请求,并转变成一个模型model

1.2 实现方法

  • (1)实现接口的方式
    • 实现方法和之前一样,但是把配置的处理器 和 适配器删掉也能够正常运行,正常开发是不需要配置这两样东西的,为了将原理才使用
    • 缺点:一个实现Controller接口的类,只能实现一个方法,导致需要创建大量的类
    • 实现Controller接口方法比较旧,已经不推荐使用了
1
2
3
4
5
6
7
8
9
10
11
12
public class ControllerTest1 implements Controller {
//函数式接口,只有一个方法,就是返回一个ModelAndView类的对象
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();

mv.addObject("msg", "Test1");
mv.setViewName("test");

return mv;
}
}
  • (2)以添加@Controller注解方式实现
    • 学Spring也讲过其他注解@Component @Service @Repositort,功能都一样,就是为了区分而已
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller //代表这个类会被Spring进行接管,这个注解的类中所有方法,如果返回值是String,且有具体的页面可以跳转,就可以被视图解析器解析。
public class ControllerTest2 {

//请求映射访问
@RequestMapping("/t2")
public String test1(Model model){
model.addAttribute("msg", "ControllerTest2");
return "test";
}

@RequestMapping("/t3")
public String test3(Model model){
model.addAttribute("msg", "ControllerTest3");
return "test";
}
}

二、结果跳转方式

2.1 原生的ServletAPI

  • 通过设置ServletAPI,不需要视图解析器
    • (1)通过HttpServeltResponse进行输出
    • (2)通过HttpServletResponse实现重定向
    • (3)通过HttpServletResponse实现转发

2.2 通过ModelAndView

  • 通过setViewName("")方法来设置View名称,通过视图解析器跳转到指定页面
    • 页面:{视图解析器前缀} + viewName + {视图解析器后缀}

2.3 SpringMVC

  • 创建String的返回方法
  • (1)无需视图解析器
    • return "/index.jsp" jsp页面的全类名
    • 转发:return "forward:/index.jsp"
    • 重定向:return "redirect:index.jsp"
  • (2)视图解析器
    • return "具体的jsp名称"
    • 重定向:return "redirect:index.jsp" 重定向仍然要写全类名

三、ResutFul风格

3.1 介绍

  • 普通风格访问页面:localhost:8080/mehtod?add=1&...

  • RestFul风格:localhost:8080/mehtod/add/1/2/...

  • ResutFul是一个资源定位操作风格,软件可以更简洁,更有层次,更易于实现缓存机制

3.2 资源操作方式

  • 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作
    • 分别对应:添加,删除,修改,查询
  • 传统方式操作资源:通过不同的参数来实现不同的效果,每个链接都不相同
    • http://xxx.xxx.com/item/queryItem.aciton?id=1 查询:GET
    • http://xxx.xxx.com/item/saveItem.aciton 新增:POST
    • http://xxx.xxx.com/item/updateItem.aciton 更新:POST
    • http://xxx.xxx.com/item/deleteItem.aciton?id=1 删除:GET/POST
  • resutFul操作资源:通过不同的请求方式来实现不同效果(链接接一样,功能不同)
    • http://xxx.xxx.com/item/1 查询:GET
    • http://xxx.xxx.com/item 新增:POST
    • http://xxx.xxx.com/item 更新:PUT
    • http://xxx.xxx.com/item/1 删除:DELETE

3.3 实现方法

  • (1)基本实现:使用@PathVariable,让参数的值绑定到URM模板上
1
2
3
4
5
6
7
8
9
10
11
/*
resultFul风格:
在Spring MVC中可以使用@PathVariable注解,让方法参数的值对应绑定到一个URM模板变量上
网页输入:http://localhost/add2/1/2
*/
@RequestMapping("/add2/{a}/{b}")
public String test2(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg", "结果为:"+res);
return "test";
}
  • (2)实现同一链接,不同功能
    • 设置参数method,传入参数为RequestMethod对象,是个枚举类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
限制发送请求的方式
public enum RequestMethod {
GET, //GET请求
HEAD,
POST, //POST请求
PUT, //PUT请求
PATCH,
DELETE, //DELETE请求
OPTIONS,
TRACE;
来限定访问的方法
*/
@RequestMapping(value="/add3/{a}/{b}", method = RequestMethod.GET)
public String test3(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg", "结果为:"+res);
return "test";
}
  • (3)通过注解实现同一链接,不同方法
    • 通过一下注解来取代@RequestMappng()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
上面方式的简化版
通过请求映射访问注解
@GetMapping
@DeleteMapping
@PostMapping
@PutMapping
@PatchMapping
*/
@GetMapping("/add4/{a}/{b}") //GET请求
public String test4(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg", "GET结果为:"+res);
return "test";
}

@PostMapping("/add4/{a}/{b}") //POST请求
public String test5(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg", "POST结果为:"+res);
return "test";
}

四、数据处理

4.1 处理提交数据

  • (1)正常方法
    • ?参数名=参数值
1
2
3
4
5
6
7
8
9
10
11
12
//  http://localhost:8080/user/t1?name=莱特雷
@GetMapping("/user/t1")
public String test1(String name, Model model){
//1.接受前端数据
System.out.println(name);

//2.将返回的结果传递给前端(通过Model)
model.addAttribute("msg", name);

//3.视图跳转
return "test";
}
  • (2)起别名
    • @RequestParam("")起个别名,再用上面方法传参
1
2
3
4
5
6
7
8
9
10
11
12
13
//  http://localhost:8080/user/t2?username=莱特雷
// 前端需要用到的参数,无论名字相不相同,都起个别名
@GetMapping("/user/t2")
public String test2(@RequestParam("username") String name, Model model){
//1.接受前端数据
System.out.println(name);

//2.将返回的结果传递给前端(通过Model)
model.addAttribute("msg", name);

//3.视图跳转
return "test";
}
  • (3)前端接受是一个对象时
    • 把创建对象所需要的值进行传递,?参数=值&?参数=值?参数=值...
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
38
39
40
public class User {
private int id;
private String name;
private int age;

public User(){}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//前端接受的是一个对象:id, name, age
// http://localhost:8080/user/t3?id=0&name=莱特雷&age=21
/*
内部执行流程
(1)接受前段用户传递的参数。判断参数的名字,假设名字直接在方法上,可以直接使用。
(2)假设传递的是对象,则会对象中的字段名,名字一样则传递成功
*/
@GetMapping("/user/t3")
public String test3(User user, Model model){
//1.接受前端数据
System.out.println(user);

//2.将返回的结果传递给前端(通过Model)
model.addAttribute("msg", user);

//3.视图跳转
return "test";
}

4.2 将后台的数据显示到前端

  • (1)ModelAndView
    • 通过public ModelAndView addObject(String attributeName, @Nullable Object attributeValue)来封装数据给前端
  • (2)Model
    • 通过 Model addAttribute(String var1, @Nullable Object var2)来封装数据给前端
  • (3)ModelMap
    • ModelMap:继承与LinkHashMap,所以他拥有LinkedHashMap的全部功能
  • (4)对比
    • Model: 只有几个方法只适合用于存储数据,简化了新手对于Model对象的操作和理解(推荐使用)
    • ModelMap:继承了LinkMap,处理时限了自身的一些方法,同样继承LinkMap的方法和特性
    • ModelAndView:可以穿出数据的同时,可以进行设置返回的逻辑视图,进行跳转

五、解决乱码问题

5.1 乱码出现

  • (1)控制器创建一个请求方式为POST的方法
1
2
3
4
5
6
7
8
9
10
11
12
@Controller
public class EncodingController {

//post方法提交中文,会出现乱码
//通过过滤器解决
@PostMapping("/encode/t1")
public String test1(String name, Model model){
System.out.println(name);
model.addAttribute("msg", name);
return "test";
}
}
  • (2)创建一个表单jsp,跳转到该控制器,使用post方法
1
2
3
4
5
6
7
8
9
10
11
12
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/encode/t1" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>
  • (3)目录结构如下

5.2 乱码解决

  • 由于post方法提交数据,会导致数据变成乱码,解决方法可以将post方法换成get
  • 如果仍然用post方法提交,则需要使用到过滤器了
  • (1)使用自定义过滤器
    • 类实现Filter接口,重写doFilter方法
    • 在web.xml中注册自定义过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
过滤器
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");//将编码调回utf-8
servletResponse.setCharacterEncoding("utf-8");

filterChain.doFilter(servletRequest, servletResponse);
}

@Override
public void destroy() {

}
}
1
2
3
4
5
6
7
8
9
10
11
web.xml文件
<!--1.自定义过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.letere.filter.EncodingFilter</filter-class>
</filter>
<!--过滤所有的请求-->
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern> <!--因为我们是直接通过form.jsp访问,所以使用/*拦截jsp页面-->
</filter-mapping>
  • (2)使用SpringMVC自带的过滤器
    • 直接在web.xml注册自带的过滤器CharacterEncodingFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
web.xml文件
<!--2.使用Spring自带的过滤器
缺点,会对GET方法不友好
-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!--设置编码集为utf-8-->
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern> <!--因为我们是直接通过form.jsp访问,所以使用/*拦截jsp页面-->
</filter-mapping>