DispatcherServlet
•请求(HttpServletRequest):获取请求数据
•响应(HttpServletResponse):设置响应数据
HttpServletRequest 和 HttpServletResponse
ServletRequest 和 HttpServletRequest 接口详解-优快云博客
BS架构和CS架构
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 (维护方便 体验一般)
CS架构:Client/Server,客户端/服务器架构模式。(开发、维护麻烦 体验不错)
请求
Postman
Postman 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件。
作用:常用于进行接口测试
安装:
简单参数
简单参数:在向服务器发起请求时,向服务器传递的是一些普通的请求数据。
原始方式(仅做了解,在以后的开发中不会使用到)
在原始的web程序中,获取请求参数,需要通过HttpServletRequest 对象手动获取。
在原始的 Web 程序当中,需要通过 Servlet 中提供的 API:HttpServletRequest(请求对象),获取
请求的相关信息。比如获取请求参数: Tomcat 接收到 http 请求时:把请求的相关信息封装到 HttpServletRequest 对象中
在 Controller 中,我们要想获取 Request 对象,可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息:
//1. 简单参数
//原始方式
@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方式
如果是简单参数,参数名与形参变量名相同,定义同名的形参即可接收参数。
//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name, Integer age){
System.out.println(name+ ":" + age);
return "OK";
}
结论:不论是 GET 请求还是 POST 请求,对于简单参数来讲,只要保证请求参数名和 Controller 方法中的形参名保持一致 ,就可以获取到请求参数中的数据值。
参数名不一致
结论:运行没有报错。对于简单参数来讲,请求参数名和 controller 方法中的形参名不一致时,无法接收到请求数据。
简单参数:如果方法形参名称与请求参数名称不匹配,可以使用 @RequestParam 完成映射。
// @RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){
System.out.println(username+ ":" + age);
return "OK";
}
@RequestParam 中的 required 属性默认为 true,代表该请求参数必须传递,如果不传递将报错。 如果该参数是可选的,可以将 required 属性设置为 false。
小结
实体参数
简单实体对象
简单实体对象:请求参数名与形参对象属性名相同,定义 POJO 接收即可
//2. 实体参数
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}
public class User {
private String name;
private Integer age;
}
复杂实体对象
复杂实体对象:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数。
数组集合参数
数组集合参数的使用场景:在 HTML 的表单中,有一个表单项是支持多选的(复选框),可以提交选择的多个值。
数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数
//3. 数组集合参数
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(Arrays.toString(hobby));
return "OK";
}
集合
集合参数:请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}
日期参数
日期参数:使用 @DateTimeFormat 注解完成日期参数格式转换,以及其 pattern 属性来设置日期的格式。
Json参数
JSON 参数:JSON 数据 键名 与形参对象 属性名 相同,定义 POJO 类型形参即可接收参数,需要使用 @RequestBody 标识
路径参数
路径参数:通过请求 URL 直接传递参数,使用{…}来标识该路径参数,需要用 @PathVariable 获取路径参数
//6. 路径参数
@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);
System.out.println(name);
return "OK";
}
总结
响应
响应数据
@ResponseBody
类型:方法注解、类注解
位置:Controller 方法上/类上
作用:将方法返回值直接响应,如果返回值类型是 实体对象/集合 ,将会转换为 JSON 格式响应
说明:@RestController = @Controller + @ResponseBody
/**
* 测试响应数据
*/
@RestController
public class ResponseController {
@RequestMapping("/hello")
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;
}
}
统一响应结果
前端:只需要按照统一格式的返回结果进行解析(仅一种解析方案),就可以拿到数据。
统一的返回结果使用类来描述,在这个结果中包含:
- 响应状态码:当前请求是成功,还是失败
- 状态码信息:给页面的提示信息
- 返回的数据:给前端响应的数据(字符串、对象、集合)
/**
* 统一响应结果封装类
*/
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 +
'}';
}
}
@RestController
public class ResponseController {
@RequestMapping("/hello")
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);
}
}
分层解耦
三层架构
那其实我们上述案例的处理逻辑呢,从组成上看可以分为三个部分:
- 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。
- 逻辑处理:负责业务逻辑处理的代码。
- 请求处理、响应数据:负责,接收页面的请求,给页面响应数据。
Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
Service:业务逻辑层。处理具体的业务逻辑。
Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
分层解耦
- 内聚:软件中各个功能模块内部的功能联系。
- 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
- 软件设计原则:高内聚低耦合。
控制反转: Inversion Of Control,简称 IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入: Dependency Injection,简称 DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为bean。
IOC&DI
①. Service 层 及 Dao 层的实现类,交给 IOC 容器管理。
②. 为 Controller 及 Service 注入运行时,依赖的对象。
③. 运行测试。
IOC详解
bean的声明
要把某个对象交给 IOC 容器管理,需要在对应的类上加上如下注解之一:
注意事项:
- 声明 bean 的时候,可以通过 value 属性指定 bean 的名字,如果没有指定,默认为类名首字母小写。
- 使用以上四个注解都可以声明 bean,但是在 springboot 集成 web 开发中,声明控制器 bean 只能用 @Controller。
bean组件扫描
- 前面声明 bean 的四大注解,要想生效,还需要被组件扫描注解 @ComponentScan 扫描。
- @ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包及其子包。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
DI详解
@Autowired注解,默认是按照 类型 进行,如果存在多个相同类型的bean,将会报出如下错误:
通过以下几种方案来解决:
- @Primary
- @Qualifier
- @Resource
@Primary
@Service
public class EmpServiceA implements EmpService {
}
@RestController
public class EmpController {
@Autowired
@Qualifier("empServiceA")
private EmpService empService ;
@RestController
public class EmpController {
@Resource(name = "empServiceB")
private EmpService empService ;
@Autowird 与 @Resource的区别
- @Autowired 是 spring 框架提供的注解,而 @Resource 是 JDK 提供的注解
- @Autowired 默认是按照类型注入,而 @Resource 是按照名称注入
小结
上一节:
SpringBootWeb入门、 HTTP协议 、WEB服务器-Tomcat(day04)-优快云博客