浅析SpringMvc中参数的解耦
springmvc中请求参数的耦合
这里所说的是请求时的参数耦合
在javaweb我们常常用request对象来获得请求中的参数
如果request获得的参数名称不匹配,那么获得的参数就为null
比如下面的代码---->>
package com.gavin.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
public class testController {
@RequestMapping("/tolog.do")
public String toLogin(HttpServletRequest request, HttpServletResponse resp) {
String username = request.getParameter("username");
String password = request.getParameter("password");
// 连接数据库查询
System.out.println(username + "--" + password);
return "success";
}
}
假如请求时参数不匹配,即我们的请求参数只能是username和password
这时候如果改变就会得不到想要的参数;
所以需要一种方式来实现低耦合,不用request对象获得参数并能获得请求时的参数
@RequestMapping("/tologg.do")
public String toLogin(String username, String password) {
// 连接数据库查询
System.out.println(username + "--" + password);
return "success";
}
这里也是要求请求时的参数要和方法中的参数名一致,如果不一致---->>
那怎么实现解耦合?
我们可以指定请求时的参数别名
@RequestMapping("/tologgg.do")
public String toLog(@RequestParam("name") String username,@RequestParam("pwd") String password) {
// 连接数据库查询
System.out.println(username + "--" + password);
return "success";
}
使用这种方式还可以自动实现类型的转换
有时候接收前端的参数太多像这样
后端接收
这时候就要将参数封装为一个类来实现
POJO类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TPerson {
String name;
Integer age;
String gender;
String[] hobby;
String birth;
}
这样如果参数发生了变化,我们需要修改TPerson类中的属性而不是方法
有时候在pojo解耦时会出现no getter 的错误,此时在参数pojo上添加注解@Param("pojo实例名")
即可
springmvc底层是通过getset方法来实现参数的解析—即反射的方式,所以类中必须要有无参构造方法;
这里会涉及到一个问题就是对于一些基本类型的转换是可以的,如果是日期类型的,那会提示转换失败
其实原因很简单,关于日期的转换格式不知道,所以,无法进行解析
日期类型转换
那如果放在实体类中
我们看到既然注解放在参数上时时可以识别日期,那同样我们将注解放到TPerson类中的属性上
除了上述的注解转换方式,spring还提供了转换接口
import lombok.SneakyThrows;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDate implements Converter<String, Date> {
SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd");
@SneakyThrows//偷偷默默的抛出异常的注解
@Override
public Date convert(String source) {
Date date = dateFormat.parse(source);
return date;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TPerson {
String name;
Integer age;
String gender;
String[] hobby;
// @DateTimeFormat(pattern = "yyyy-MM-dd")
Date birth;
@Override
public String toString() {
return "TPerson{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", hobby=" + Arrays.toString(hobby) +
", birth='" + birth + '\'' +
'}';
}
}
请求后-----
害,没有配置转换类,
在配置文件中配置转换类
先看一下要使用的接口
再次请求后得到结果,
可以看到明明通过一个注解的方式解决,却要费尽心思用一个转换类加配置
类解决,显然不是一个方便的方式;
List参数的解耦
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="dodo.do">
名称:<input name="fruitList[0].fruitName"></br>
种类:<input name="fruitList[0].fruitType"></br>
名称:<input name="fruitList[1].fruitName"></br>
种类:<input name="fruitList[1].fruitType"></br>
<input type="submit" value="提交">
</form>
</body>
</html>
后端—>
package com.gavin.pojo;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* t_user
* @author
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TUser implements Serializable {
private Integer userId;
private String userName;
private String loginName;
private String password;
private Integer roleId;
private String tel;
private Date registerTime;
private String status;
/**
* 一个用户对应一个角色
*/
private TRole tRole;
private static final long serialVersionUID = 1L;
private List<Fruit> fruitList;
}
@RequestMapping("/dodo.do")
public String dododo(TUser tUser){
System.out.println(tUser.getFruitList());
return "success";
}
这里相当于遍历集合中的元素,按照下标的形式进行装配
map类型参数
跟list一样,
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form method="post" action="dodo.do">
名称:<input name="fruitCount['fruit'].fruitName"></br>
种类:<input name="fruitCount['fruit'].fruitType"></br>
名称:<input name="fruitCount['1'].fruitName"></br>
种类:<input name="fruitCount['1'].fruitType"></br>
<input type="submit" value="提交">
</form>
</body>
</html>
后端
@RequestMapping("/dodo.do")
public String dododo(TUser tUser){
System.out.println(tUser.getFruitCount());
return "success";
}
只要满足键值对关系就可以了
restful风格的参数
说到这个restful风格,说起来也和常见,比如
链接一下baidu.com
这个就是一种restful风格的解析
在springmvc中怎么用着种风格呢?
我记得之前在某一篇帖子种写了这种方式, 看链接
请求转发与响应重定向
基础知识请看这个链接
后端—>
@RequestMapping("testForward.do")
public String testForward() {
System.out.println("testForward");
return "1234.jsp";
}
@RequestMapping("testForward1.do")
public String testForward1() {
System.out.println("testForward1");
return "/1234.jsp";
}
@RequestMapping("testRedirect.do")
public String testRedirect() {
System.out.println("testForward1");
return "redirect:1234.jsp";
}
<form method="get" action="testForward.do">
<input type="submit" value="testForward"/>
</form>
<form method="get" action="testForward1.do" >
<input type="submit" value="testForward1" />
</form>
<form method="get" action="testRedirect.do" >
<input type="submit" value="testRedirect" />
</form>
通过view来完成请求转发与重定向
@RequestMapping("/viewForward1.do")
public View viewForward1(HttpServletRequest request){
View view=null;
System.out.println("viewForward1");
// 请求转发
// view= new InternalResourceView("/1234.jsp");
// 重定向
view=new RedirectView(request.getContextPath()+"/1234.jsp");
return view;
}
}
<form method="get" action="viewForward1.do" >
<input type="submit" value="viewForward1" />
</form>
通过ModelAndView 来完成请求转发与重定向;
@RequestMapping("/viewForward.do")
public Object viewForward(HttpServletRequest request) {
System.out.println("viewForward");
ModelAndView model = new ModelAndView();
// model.setViewName("1234.jsp");
// model.setViewName("redirect:1234.jsp");
// model.setView(new InternalResourceView("/1234.jsp"));
model.setView(new RedirectView(request.getContextPath()+"/1234.jsp"));
return model;
}
小结:
可以通过 返回值来直接完成请求转发或者重定向,
可以通过View接口/ModelAndView接口来实现
实际上一般是通过Model model/ModelAndView来在请求转发时添加一些数据;可以看到ModelAndView 可以通过setview方法传入view参数实现请求转发与响应重定向;
Json数据的发送与接收
@RequestMapping("/searchUser.do")
@ResponseBody
public User searchUser() {
User user= new User(88,"gavin","123");
return user;
}
json数据的传递来龙去脉
为便于理解,做以下逐级递进
//普通格式
@RequestMapping("/searchUser.do")
@ResponseBody
public User searchUser(@RequestParam("name") String name,@RequestParam("pwd") String pwd) {
System.out.println(name+pwd);
User user= new User(88,"gavin","pwd");
return user;
}
// pojo对象格式
@RequestMapping("/searchUserd.do")
@ResponseBody
public User searchUserd(User users) {
System.out.println(users);
User user= new User(88,"gavin","pwd");
return user;
}
前端测试---->>
<%--
Created by IntelliJ IDEA.
User: Gavin
Date: 2021/12/20
Time: 19:46
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" %>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="get" action="toInfo.do/10">
id号<input type="text" name="id" placeholder="请输入账号"/><br>
<input type="submit" value="toget"/>
</form>
<form method="post" action="toInfo.do/10">
id号<input type="text" name="id" placeholder="请输入账号"/><br>
<input type="submit" value="topost"/>
</form>
<form method="post" action="toInfo.do/10">
id号<input type="text" name="id" placeholder="请输入账号"/><br>
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="toput"/>
</form>
<form method="get" action="toInfo.do/10">
id号<input type="text" name="id" placeholder="请输入账号"/><br>
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="todel"/>
</form>
<form method="get" action="testVoid.do">
<input type="submit" value="testVoid"/>
</form>
<form method="get" action="testForward.do">
<input type="submit" value="testForward"/>
</form>
<form method="get" action="testForward1.do">
<input type="submit" value="testForward1"/>
</form>
<form method="get" action="testRedirect.do">
<input type="submit" value="testRedirect"/>
</form>
<form method="get" action="viewForward.do">
<input type="submit" value="viewForward"/>
</form>
<form method="get" action="viewForward1.do">
<input type="submit" value="viewForward1"/>
</form>
<form method="get" action="ModelAndViewForward1.do">
<input type="submit" value="ModelAndViewForward1"/>
</form>
<form>
姓名:<input name="name" id="name" type="text">
密码:<input name="pwd" id="pwd" type="text">
<input type="button" value="searchUser" onclick="search()"/>
</form>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.min.js" type="text/javascript">
</script>
<script type="text/javascript">
function search() {
var str=$("#name").val();
var str1= $("#pwd").val();
$.ajax({
url: "${pageContext.request.contextPath}/searchUserd.do?name="+str+"&pwd="+str1,
type:"get",
// data: JSON.stringify({'name':'123','pwd':'123'}),
// dataType: "json",
contentType: "application/json;charset=UTF-8",
success: function (data) {
alert(data.name + data.pwd);
}
});
}
</script>
</body>
</html>
@RestController
//@Controller
public class testController {
@RequestMapping("/searchUser.do")
@ResponseBody
public User searchUser(@RequestParam("name") String name,@RequestParam("pwd") String pwd) {
System.out.println(name+pwd);
User user= new User(88,"gavin","pwd");
return user;
}
@RequestMapping("/searchUserDemo.do")
public User searchUser() {
User user= new User(88,"gavin","pwd");
return user;
}
@RequestMapping("/searchUserd.do")
@ResponseBody
public User searchUserd(User users) {
System.out.println(users);
User user= new User(88,"gavin","pwd");
return users;
}
}
如果返回的数据都是json格式的.可以直接在类上加注解 @RestController来简化每个方法上的@RequesponseBody注解
逐渐将数据替换为json格式
<form>
id:<input name="id" id="id" type="text"/>
姓名:<input name="name" id="name" type="text"/>
密码:<input name="pwd" id="pwd" type="text"/>
<input type="button" value="searchUser" onclick="search()"/>
</form>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.min.js" type="text/javascript">
</script>
<script type="text/javascript">
function search() {
var str0=$("#id").val();
var str=$("#name").val();
var str1=$("#pwd").val();
$.ajax({
url: "${pageContext.request.contextPath}/searchUserd.do",
type:"post",
data: JSON.stringify({id:$("#id").val(),name:$("#name").val(),"pwd":$("#pwd").val()}),
dataType: "json",
contentType: "application/json;charset=UTF-8",
success: function (data) {
alert(data.id+data.name + data.pwd);
}
});
}
</script>
</body>
</html>
后端—>>
@RequestMapping("/searchUserd.do")
@ResponseBody
public User searchUserd(@RequestBody User users) {
System.out.println(users);
User user= new User(88,"gavin","pwd");
return users;
}
@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);而最常用的使用请求体传参的无疑是POST请求了,所以使用@RequestBody接收数据时,一般都用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
RequestBody 与RequestParam的区别
可以这么理解,RequestBody是接收前端json字符串的,{key:value}
RequestParam是接收前端参数的 key=value
DateTimeFormat与 JsonFormat的区别
DateTimeFormat----参数格式
JsonFormat—响应数据格式
先看案例—>>
一个实体类
package com.gavin.pojo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Repository;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Repository(value = "player")
public class Player {
private String name;
private int age;
@DateTimeFormat(pattern = "yyyy-MM-dd")//声明一个字段或方法参数应该被格式化为日期或时间。
//处理响应json 数据的处理, pattern :指定响应时间日期的格式 , Timezone:指定响应的时区,否则会有8个小时的时间差
@JsonFormat(pattern = "yyyy-MM-dd" ,timezone = "UTC-8")
private Date birth;
private static final long serialVersionUID = 1L;
}
controller层
package com.gavin.dateFormat;
import com.gavin.pojo.Player;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class DateFormatController {
@RequestMapping("/toLogin.do")
@ResponseBody
public Player showInfo(@RequestBody Player player){
System.out.println("success");
return player;
}
}
前端
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
<script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.min.js"></script>
</head>
<body>
<script type="text/javascript">
function happy() {
$.ajax({
url:"${pageContext.request.contextPath}/toLogin.do",
type:"post",
data:JSON.stringify({name:"张胜男",age:18,birth:"1998-10-19"}),
dataType:"json",
contentType:"application/json;charset=UTF-8",
success:function(data){
$("#name").val(data.name);
$("#age").val(data.age);
$("#birth").val(data.birth);
}
});
}
</script>
<form >
<button type="button" onclick="happy()">注册</button>
<input name="name" id="name" type="text"/>
<input name="age" id="age" type="text"/>
<input name="birth" id="birth" type="text"/>
</form>
</body>
</html>
前端点击按钮,然后异步显示数据
要想知道区别,别然讲一万遍不如自己时间一遍;
请求结果—>>
具体的原因是这样的---->
当前端传过来的数据是一堆字符串时,这个时候可以用JSON.stringify(str)来将字符串转换为json对象;
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get
请求得到是null。