JavaWeb - 8 - 请求响应 分层解耦
请求响应
请求(HttpServletRequest):获取请求数据
响应(HttpServletResponse):设置响应数据
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端(维护方便,体验一般)
CS架构:Client/Server,客户端/服务器架构模式(开发维护麻烦、体验不错)
一.请求
1.1 Postman
Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件
作用:常用于进行接口测试
1.2 简单参数
原始方式
在原始的web程序中,获取请求参数,需要通过HttpServletRequest对象手动获取
· Controller方法形参中声明HttpServletRequest对象
· 调用对象的getParameter(参数名)
SpringBoot方式
· 简单参数:参数名与形参变量名相同,定义形参即可接收参数(会自动进行类型转换)
· 简单参数:如果方法形参名称与请求参数名称不匹配,可以使用@RequestParam完成映射
注意事项:@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false
1.3 实体参数
简单实体对象:请求参数名与形参对象属性名相同,定义POJO接收即可
复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
1.4 数组集合参数
数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数
集合参数:请求参数名与形参集合名称相同且请求参数为多个,@RequestParam绑定参数关系
1.5 日期参数
日期参数:使用@DateTimeFormat注解完成日期参数格式转换
1.6 JSON参数
JSON参数:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数,需要使用@RequestBody标识
1.7 路径参数
路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数
/**
* 测试请求参数接收
*/
@RestController
public class RequestController {
//原始方式
// @RequestMapping("/simpleParam")
// public String simpleParam(HttpServletRequest request){
// //获取请求参数
// String name = request.getParameter("name");
// String ageStr = request.getParameter("age");
//
// int age = Integer.parseInt(ageStr);
//
// System.out.println(name + ":" + age);
//
// return "OK";
// }
//springboot方式
//简单参数GET
// @RequestMapping("/simpleParam")
// public String simpleParam(String name, Integer age){
// System.out.println(name + ":" + age);
// return "OK";
// }
//简单参数POST
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name="name", required = false) String username, Integer age){
System.out.println(username + ":" + age);
return "OK";
}
//简单实体参数
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}
//复杂实体参数
@RequestMapping("/complexPojo")
public String complexPojo(User user){
System.out.println(user);
return "OK";
}
//数组参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "OK";
}
//集合参数
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}
//日期时间参数
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}
//json参数
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
//路径参数
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id){
System.out.println(id);
return "OK";
}
@RequestMapping("/path/{id}/{name}")
public String pathParam2(@PathVariable Integer id, @PathVariable String name){
System.out.println(id + ":" + name);
return "OK";
}
}
二.响应
2.1 @ResponseBody
类型:方法注解、类注解
位置:Controller方法上/类上
作用:将方法返回值直接响应,如果返回值类型是实体对象/集合,将会转换为JSON格式响应
说明:@RestController = @Controller + @ResponseBody
2.2 统一响应结果
Result(code、msg、data)
/**
* 测试响应数据
*/
@RestController
public class ResponseController {
// @RequestMapping("/hellohello")
// public String hello(){
// System.out.println("Hello World ~");
// return "Hello World ~";
// }
//
// @RequestMapping("/getAddr")
// public Address getAddr(){
// Address addr = new Address();
// addr.setProvince("广东");
// addr.setCity("深圳");
// return addr;
// }
//
// @RequestMapping("/listAddr")
// public List<Address> listAddr(){
// List<Address> list = new ArrayList<>();
//
// Address addr = new Address();
// addr.setProvince("广东");
// addr.setCity("深圳");
//
// Address addr2 = new Address();
// addr2.setProvince("陕西");
// addr2.setCity("西安");
//
// list.add(addr);
// list.add(addr2);
// return list;
// }
@RequestMapping("/hello1")
public Result hello(){
System.out.println("Hello World ~");
//return new Result(1,"success","Hello World ~");
return Result.success("Hello World ~");
}
@RequestMapping("/getAddr")
public Result getAddr(){
Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");
return Result.success(addr);
}
@RequestMapping("/listAddr")
public Result listAddr(){
List<Address> list = new ArrayList<>();
Address addr = new Address();
addr.setProvince("广东");
addr.setCity("深圳");
Address addr2 = new Address();
addr2.setProvince("陕西");
addr2.setCity("西安");
list.add(addr);
list.add(addr2);
return Result.success(list);
}
}
/**
* 统一响应结果封装类
*/
public class Result {
private Integer code ;//1 成功 , 0 失败
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 Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = 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);
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
2.3 案例
//Controller.EmpController.java
@RestController
public class EmpController {
@RequestMapping("/listEmp")
public Result list(){
//1.加载并解析emp.xml
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
//2.对数据进行转换处理 - gender, job
empList.stream().forEach(emp -> {
//处理gender 1:男 2:女
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
}else if("2".equals(gender)){
emp.setGender("女");
}
//处理job 1: 讲师, 2: 班主任 , 3: 就业指导
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
}else if("2".equals(job)){
emp.setJob("班主任");
}else if("3".equals(job)){
emp.setJob("就业指导");
}
});
//3.响应数据
return Result.success(empList);
}
}
三.分层解耦
3.1 三层架构
Controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据
Service:业务逻辑层,处理具体的业务逻辑
Dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增删改查
3.2 分层解耦
· 内聚:软件中各个功能模块内部的功能联系
· 耦合:衡量软件中各个层/模块之间的依赖、关联的程度
· 软件设计原则:高内聚低耦合
控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转
依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入
Bean对象:IOC容器中创建、管理的对象,称之为bean
3.3 IOC & DI入门
如果有多个实现类(A、B),需要切换实现类,通过注释@Component实现切换(用A的时候在A中加入@Component,用B的时候在B中加入@Component)
3.4 IOC详解
Bean的声明
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一(@Component @Controller @Service @Repository)
注意事项
· 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写
· 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller
Bean组件扫描
· 前面声明bean的四大注解,想要生效,还需要被组件扫描注解@ComponentScan扫描
· @ComponentScan注解虽然没有显式配置,但实际上已经包含在了启动类声明注解@SpringBootApplication中,默认扫描的范围是启动类所在包及其子包
3.5 DI详解
· @Autowired注解,默认是按照类型自动装配,如果存在多个相同类型的bean,将会报出如下错误:
通过以下几种方案来解决:@Primary、@Autowired+@Qualifier("bean的名称")、@Resource(name = "bean的名称")
注意:@Resource与@Autowired区别
· @Autowired是spring框架提供的注解,而@Resource是JDK提供的注解
· @Autowired默认是按照类型注入,而@Resource默认是按照名称注入