前言
这是javaweb第五天的学习内容主要包含了浏览器对web服务器发送请求后,服务器端对请求中各种类型参数的处理和响应处理方式,仅供个人学习使用,如果也对你有所帮助,小子深感荣幸。
一、请求
1.简单参数
即一些简单的基本数据类型
- 原始方法:通过HttpServletRequest对象手动获取(了解,很少用)
@RequestMapping("/simpleParam")
public String simpleParam(HttpServletRequest request){ //这个填充是有SpringMVC框架来实现执行的,它会将服务器从请求信息中提取到的HttpServletRequset对象填充到方法的参数中
String name = request.getParameter("name");
String age = request.getParameter("age");
int a = Integer.parseInt(age);
System.out.println(name+":"+age);
return "ok";
}
- 通过SpringBoot
1)要参数名和形参变量名保持相同即可,springboot会自动进行参数的类型转换和填充
@RequestMapping("/simpleParam")
public String simpleParam(String name,int age){
System.out.println(name+":"+age);
return "ok";
}
2)如果参数名和变量名没有保持一致,则需要在方法中使用@RequestParam注解进行参数的映射
//请求参数为name:tom age:10
@RequestMapping("/simpleParam")
public String simpleParam(String username,int age){
System.out.println(username+":"+age); //打印为null:10,因为请求中的参数为name,这里使用的是使用springboot自动填充,所以会从请求体中找名字也是username的参数进行填充,但是没有找到,所以返回了null,打印出来就是null
return "ok";
}
@RequestMapping("/simpleParam")
public String simpleParam(@RequsetParam("name") String username,int age){ //使用@RequestParam注解进行参数的绑定,会将括号中的参数同后面跟随的形参进行绑定(其实@RequsetParam注解中还有其他的参数,其中一个参数叫做required,表示该请求参数是否必须传递,默认为true,如果不传递就会报错)
System.out.println(username+":"+age); //打印tom:10
return "ok";
}
2.实体参数
在使用简单参数进行数据传递时,前端传递了多少个请求参数,后端的controller方法就需要写多少个参数用来接收,比较繁琐。
可以考虑将请求参数封装到一个实体类对象中。如果要完成数据封装,需要遵守如下规则:请求参数名与实体类的属性名相同
2.1 简单实体对象
需要定义POJO对象用于进行请求参数数据的封装(POJO:普通java对象,不依赖任何框架的简单java类,一般只包含属性和方法)
//关于这个POJO,要求包含无参构造,Springboot会通过无参构造来创建实例化对象,同时还要有对应的get和set方法,以便Springboot可以进行属性值的读写
//和springboot自动填充简单参数一样,如果使用实体参数,springboot会先进行数据类型的转换,然后再将数据填入到POJO对象中;同时也要求POJO中属性值的名称必须要和请求信息中的参数名称保持一致,否则Springboot会无法正确的进行数据的填充
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//和javaBean类有相似之处,但是POJO并不需要严格遵守javaBean类的规则
//以下为controller方法
@RestController
public class RequestController {
//实体参数:简单实体对象
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}
}
2.2 复杂实体参数
其实基本和简单实体参数一样,只不过在实体POJO的定义中引入了另一个POJO的定义,只需要被引用的POJO中的属性名也同请求信息中的参数名保持一致即可。(被引用的POJO中同样需要无参构造和get、set方法,以此确保springboot可以正确的实现对应参数的填充)
3.数组集合参数
如果前端的某个表单中提交了多个名称相同但是值不同的参数信息,一般在后台会通过使用数组(默认)或者集合来进行接收。
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "ok";
}
//默认是使用数组来进行接收的,如果希望使用集合来进行参数信息的接收,需要使用@RequestParam注解进行参数绑定
@RequestMapping("/arrayListParam")
public String arrayListParam(@RequestParam ArrayList<String> hobby){ //关于RequsetParam注解:用于进行传递参数名称和形参名称不同时的绑定。如果请求参数信息中的参数只有一个,且和形参名称相同,则不需要在注解后添加参数指明绑定参数,否则需要指明当前形参绑定的是请求参数中的哪一个。
System.out.println(hobby);
return "ok";
}
4.日期参数
如果需要接收由前端传回的日期参数,需要使用注解@DateTimeFormat(patter=“…”)来指明日期数据的格式(前端需要按照指定格式来进行日期数据的传递),后端需要使用Date或者LoaclDateTime类型来对请求参数进行封装。
5.JSON参数
当前后端在传递一些比较复杂的数据信息时可以使用JSON进行数据的封装,封装规则:JSON数据键名与形参对象属性名相同
后端在接受JSON数据时候,需要使用@RequestBody注解实现JSON中数据和POJO的映射。
@RestController
public class RequestController {
//JSON参数
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
}
6.路径参数
路径参数即通过将传递给后端的参数直接添加在url后面的方式来实现参数的传递。(post方法是将请求信息装载到消息体或者叫请求体中,set方法是以“url?param1 = … & param2 = … …”的形式通过url来实现参数传递)
后端如果希望接收前端发出的路径参数,需要使用@PathVariable注解进行参数的绑定
(路径参数可以有多个,例如url:http://localhost:8080/path/1/beijing 这里的1和beijing都是路径参数)
@RestController
public class RequestController {
//路径参数
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id, @PathVariable String name){
System.out.println(id+ " : " +name);
return "OK";
}
}
//上图中的形参会默认的绑定到方法入口中名称相同的路径参数上,如果希望绑定到一个名称不相同的形参上,需要再@PathVariable注解中指明希望绑定的路径参数的名称
@RestController
public class RequestController {
//路径参数
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable("id") Integer num, @PathVariable String name){ //这样会将形参num和路径参数id绑定到一起,如果没有手动指明绑定的话,前端会报错
System.out.println(num+ " : " +name);
return "OK";
}
}
二、响应
关于响应部分,有一个专门的注解叫做**@ResponseBody**,可以用于修饰类或者方法,可以将返回数据作为响应数据向前端进行传递(如果是实体对象或者数组/集合,会先转换为JSON格式后再响应给浏览器)
如果用于修饰类,则表明当前类下的所有方法的返回值都会作为响应数据;
如果用于修饰方法,则表明当前方法的返回值会被作为相应数据。
如果在控制类上加入了@RestController注解,则也可以将返回数据响应给前端,原因在于@RestController注解是一个组合注解:
@RestCOntroller = @ResponseBody + @Controller
//示例:
@RequestMapping("/response")
public User[] response(){
User user = new User();
user.setName("anbeibei");
user.setAge(25);
Address address = new Address();
address.setProvince("hebei");
address.setCity("baoding");
user.setAddress(address);
User user2 = new User();
user2.setName("YoYo");
user2.setAge(24);
Address address2 = new Address();
address2.setProvince("hebei");
address2.setCity("baoding");
user2.setAddress(address2);
// ArrayList<User> arrayList = new ArrayList<>();
// arrayList.add(user);
// arrayList.add(user2);
User[] users = new User[]{user,user2};
return users;
}
返回结果:
在实际的开发中,由于前端发送的请求的响应数据可能是各种类型的,如果直接根据这个类型进行返回将会对后期的维护造成巨大的压力,所以一般会协调一个统一的返回数据类型对相应数据进行封装 ——Result类。
public class Result {
private Integer code;//1 成功 2 失败
private String msg; //提示信息
private Object data;//数据date
public Result(){
}
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public void setCode(Integer code) {
this.code = code;
}
public void setMsg(String msg) {
this.msg = msg;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public Object getData() {
return data;
}
//静态方法,方便在响应时返回数据
public static Result success(Object data){
return new Result(1,"success",data);
}
public static Result success(){
return new Result(1,"success",null);
}
public static Result error(String msg){
return new Result(0,msg,null);
}
}
三、分层解耦
在进行程序设计和程序开发时,应该尽可能遵循单一职责原则,即一个类或一个方法,应该只做一件事情,只管一块功能。这样可以降低类,接口和方法的复杂度,增强可读性和扩展性,也更加利于后期维护。
基于单一职责原则,程序的组成主要分为三个部分:
- 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。
- 逻辑处理:负责业务逻辑处理的代码。
- 请求处理、响应数据:负责,接收页面的请求,给页面响应数据。
为了能够更好的解耦,其中一个思路就是:不再手动的new对象,因为new对象的时候,如果实现类修改的话,new对象的操作可能就需要修改。通过设置一个容器,里面存储了一些对象,每当需要的时候,各个层就从这个容器中取出他们所需要的对象然后放入到本层中进行使用。由此便涉及到了Spring中的两个核心概念:IOC(控制反转)和DI(依赖注入)
**IOC(控制反转):**对象的创建控制权由程序自身转移到外部(容器,也叫IOC容器或者Spring容器),这种思想称为控制反转。
**DI(依赖注入):**容器为应用程序提供运行时所依赖的资源,称之为依赖注入。
tips:IOC容器中创建和管理的对象称为bean对象。
关于注解的一些:
@SpringBootApplication
//这个注解中集成了@ComponentScan这个注解,@ComponentScan会对指定包进行扫描,从而根据注解创建bean对象并放入容器当中。
//@SpringBootApplication注解默认的会对当前类(启动类)的包及其子包进行扫描。
//所以为了@SpringBootApplication注解可以正常的扫描当前项目中的类,一般会将类放在启动类的同一个包下。
总结
一些以前学过的内容并没有纳入本篇笔记中,主要用于个人学习,如果存在错误还请大佬指正,小子拜谢。共勉。