SpringMVCRestFul风格&数据处理及跳转
Posted a碟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVCRestFul风格&数据处理及跳转相关的知识,希望对你有一定的参考价值。
1、RestFul风格
概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
传统方式操作资源 :通过不同的参数来实现不同的效果,方法单一,post 和 get
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果,如下:请求地址一样,但是功能可以不同!
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
实际运用
在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量
下面这个例子也就是说参数a,b绑定到了URL上
package com.adie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class RestFulController {
//原来的请求:http://localhost:8080/add?a=1&b=2
//RestFul: http://localhost:8080/add/a/b
@RequestMapping(value = "/add/{a}/{b}")
public String test1(@PathVariable int a,@PathVariable int b, Model model){
int res=a+b;
model.addAttribute("msg","结果1为"+res);
return "test";
}
}
我们使用RestFul风格
- 使路径变得更加简洁;
- 获得参数更加方便,框架会自动进行类型转换。
- 通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/add/1/“10”,则路径与方法不匹配,而不会是参数转换失败。
使用method属性指定请求类型
用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
修改我们刚刚的函数为
package com.adie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class RestFulController {
//原来的请求:http://localhost:8080/add?a=1&b=2
//RestFul: http://localhost:8080/add/a/b
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.POST)
public String test1(@PathVariable int a,@PathVariable int b, Model model){
int res=a+b;
model.addAttribute("msg","结果1为"+res);
return "test";
}
}
结果
总结:
Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。所有的地址栏请求默认都会是 HTTP GET 类型的。
方法级别的注解变体有如下几个:组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping就是我们前面所用的@RequestMapping(method =RequestMethod.GET) 的组合注解。
@RequestMapping(value = “/add/{a}/{b}”,method = RequestMethod.POST)换成组合注解就是@GetMapping("/add/{a}/{b}")
这样简洁方便了许多
2、数据处理及跳转
2.1、结果跳转方式
1.ModelAndView
1.先配置视图解析器 返回的页面是{视图解析器前缀} + viewName +{视图解析器后缀}
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
2.写对应的Controller类
package com.adie.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 httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
String result="HelloSpringMVC";
//封装对象,放在ModelAndView中
mv.addObject("msg",result);
//封装要跳转的视图,放在ModelAndView
mv.setViewName("test");// /WEB-INF/jsp/test.jsp
return mv;
}
}
2.通过SpringMVC注解来实现转发和重定向
不需要视图解析器
请求转发
@Controller
public class ModelTest1 {
@RequestMapping("/m1/t1")
public String test1(Model model){
model.addAttribute("msg","进来了");
return "forward:/WEB-INF/jsp/test.jsp";
}
//请求转发
@RequestMapping("/m1/t2")
public String test2(Model model){
return "/WEB-INF/jsp/test.jsp";
}
}
重定向
@Controller
public class ModelTest1 {
@RequestMapping("/m1/t1")
public String test1(Model model){
return "redirect:/index.jsp";
}
}
加上视图解析器
重定向有无视图解析器的写法都是一样的
@Controller
public class ModelTest1 {
//请求转发
@RequestMapping("/m1/t2")
public String test2(Model model){
return "test";
}
//重定向
@RequestMapping("/m1/t1")
public String test1(Model model){
return "redirect:/index.jsp";
}
}
2.2、数据处理
1、提交的域名称和处理方法的参数名一致
// 提交数据 : http://localhost:8080/hello?name=adie
@GetMapping("t1")
public String test1(String name, Model model){
// 1.接收前端参数
System.out.println("接收到前端的参数为"+name);
// 2.将返回的结果传递给前端
model.addAttribute("msg",name);
// 3.跳转视图
return "test";
}
2、提交的域名称和处理方法的参数名不一致
这时候需要使用@RequestParam注解来统一名称
// 提交数据 : http://localhost:8080/hello?username=adie
@GetMapping("t1")
// 只要是前端的参数都加上@RequestParam(),除了可以起别名还可以用于区分是否为前端传来的参数
// 不用@RequestParam()不管前端传递过来了什么这里都能接收到,用了之后前端传递名称不对的参数会报错
public String test1(@RequestParam("username") String name, Model model){
// 1.接收前端参数
System.out.println("接收到前端的参数为"+name);
// 2.将返回的结果传递给前端
model.addAttribute("msg",name);
// 3.跳转视图
return "test";
}
只要是前端的参数都加上@RequestParam(),除了可以起别名还可以用于区分是否为前端传来的参数
不用@RequestParam()时,不管前端传递过来了什么这里都能会进入这个方法,但是用了之后前端传递名称不对的参数会报错
3、提交的是一个对象
1.我们先定义一个实体类
package com.adie.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private int age;
}
2.Controller处理方法
http://localhost:8080/user/t2?id=1&name=a碟&age=19
// 前端传递的是一个对象:id,name,age
// 1.接收前端用户的传递的参数,判断参数的名字,假设名字直接在方法上,可以直接使用
// 2.假设传递的是一个对象user,匹配user对象中的字段名:如果名字一致则行,否则匹配不到
@GetMapping("/t2")
public String test2(User user){
System.out.println(user);
return "test";
}
如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null。
2.3、数据显示到前端
1.ModelAndView
Controller使用接口定义时一般使用ModelAndView,用来封装对象和封装视图
package com.adie.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 httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
String result="HelloSpringMVC";
//封装对象,放在ModelAndView中
mv.addObject("msg",result);
//封装要跳转的视图,放在ModelAndView
mv.setViewName("test");// /WEB-INF/jsp/test.jsp
return mv;
}
}
2.Model
注解实现的SpringMVC,返回的视图就是return的值经过视图解析器后解析出来的视图。所以只需要封装模型就是封装对象
@GetMapping("t1")
public String test1(@RequestParam("username") String name, Model model){
System.out.println("接收到前端的参数为"+name);
model.addAttribute("msg",name);
return "test";
}
3. 通过ModelMap
这种使用的比较少,简单来说,Model就是简单版本的ModelMap,ModelMap继承了 LinkedMap,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性
这三种的区别简单来说
-
Model 只有几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
-
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
-
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
2.4、乱码问题处理
1.先写一个简单的表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/e/t1" method="post">
<input type="text" name="name">
<input type="submit">
</form>
</body>
</html>
2.后台处理Controller
package com.adie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class EncodingController {
// 过滤器解决乱码
@PostMapping("/e/t1")
public String test1(String name, Model model){
System.out.println(name);
model.addAttribute("msg",name);
return "test";
}
}
输入中文测试一般都会出现乱码问题
乱码在我们的做项目过程中经常会出现,这里介绍几种处理的方法
1.自己写一个过滤器处理乱码
package com.adie.filter;
import javax.servlet.*;
import java.io.IOException;
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
接着需要在web.xml中注册过滤器
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.adie.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.使用SpringMVC提供的过滤器
<filter>
<filter-name>encoding</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>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
但是这个过滤器在有些极端情况下对get请求的乱码支持不好
3.修改Tomcat的配置文件
在server.xml中配置
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
4.参考网上大佬的万能自定义过滤器的解决方法
这个过滤器很好的处理了get和post请求
package com.kuang.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
以上是关于SpringMVCRestFul风格&数据处理及跳转的主要内容,如果未能解决你的问题,请参考以下文章
学习笔记——@PathVariable注解基本使用;@PathVariable注解属性;REST风格CRUD概述;实现PUT&DELETE提交方法步骤;SpringMVC处理请求数据请求头处理