上海做高端网站制作,西安高新区网站建设,西安企业模板网站建设,网站换域名了怎么做301重定向文章目录 1 请求1.1 Postman1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 日期参数1.6 JSON参数1.7 路径参数 2 响应2.1 ResponseBody注解2.2 统一响应结果… 文章目录 1 请求1.1 Postman1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 日期参数1.6 JSON参数1.7 路径参数 2 响应2.1 ResponseBody注解2.2 统一响应结果 3 分层解耦3.1 三层架构3.1.1 介绍 3.2 分层解耦3.2.1 耦合问题3.2.2 解耦思路 3.3 IOCDI3.3.1 bean对象声明3.3.2 IOC详解3.3.3 DI详解 1 请求
1.1 Postman Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。 Postman原是Chrome浏览器的插件可以模拟浏览器向后端服务器发起任何形式(如:get、post)的HTTP请求 使用Postman还可以在发起请求时携带一些请求参数、请求头等信息 作用常用于进行接口测试 特征 简单实用美观大方
1.2 简单参数
简单参数在向服务器发起请求时向服务器传递的是一些普通的请求数据。 而在后端程序中接收普通参数数据的方式有两种
原始方式SpringBoot方式
1.2.1 原始方式
在原始的Web程序当中需要通过Servlet中提供的APIHttpServletRequest请求对象获取请求的相关信息。比如获取请求参数 Tomcat接收到http请求时把请求的相关信息封装到HttpServletRequest对象中 在Controller中我们要想获取Request对象可以直接在方法的形参中声明 HttpServletRequest 对象。然后就可以通过该对象来获取请求信息
//根据指定的参数名获取请求参数的数据值
String request.getParameter(参数名)RestController
public class RequestController {//原始方式RequestMapping(/simpleParam)public String simpleParam(HttpServletRequest request){// http://localhost:8080/simpleParam?nameTomage10// 请求参数 nameTomage10 有2个请求参数// 第1个请求参数 nameTom 参数名:name参数值:Tom// 第2个请求参数 age10 参数名:age , 参数值:10String name request.getParameter(name);//name就是请求参数名String ageStr request.getParameter(age);//age就是请求参数名int age Integer.parseInt(ageStr);//需要手动进行类型转换System.out.println(name : age);return OK;}
}1.2.2 SpringBoot方式
在Springboot的环境中对原始的API进行了封装接收参数的形式更加简单。 如果是简单参数参数名与形参变量名相同定义同名的形参即可接收参数。
RestController
public class RequestController {// http://localhost:8080/simpleParam?nameTomage10// 第1个请求参数 nameTom 参数名:name参数值:Tom// 第2个请求参数 age10 参数名:age , 参数值:10//springboot方式RequestMapping(/simpleParam)public String simpleParam(String name , Integer age ){//形参名和请求参数名保持一致System.out.println(name : age);return OK;}
}不论是GET请求还是POST请求对于简单参数来讲只要保证请求参数名和Controller方法中的形参名保持一致就可以获取到请求参数中的数据值。
1.2.3 参数名不一致
对于简单参数来讲请求参数名和controller方法中的形参名不一致时无法接收到请求数据当我们在开发中遇到了这种请求参数名和controller方法中的形参名不相同可以使用Spring提供的RequestParam注解完成映射 在方法形参前面加上 RequestParam 然后通过value属性执行请求参数名从而完成映射。代码如下
RestController
public class RequestController {// http://localhost:8080/simpleParam?nameTomage20// 请求参数名name//springboot方式RequestMapping(/simpleParam)public String simpleParam(RequestParam(name) String username , Integer age ){System.out.println(username : age);return OK;}
}注意 RequestParam中的required属性默认为true默认值也是true代表该请求参数必须传递如果不传递将报错 如果该参数是可选的可以将required属性设置为false RequestMapping(/simpleParam)
public String simpleParam(RequestParam(name name, required false) String username, Integer age){
System.out.println(username : age);
return OK;
}1.3 实体参数
在使用简单参数做为数据传递方式时前端传递了多少个请求参数后端controller方法中的形参就要书写多少个。如果请求参数比较多通过上述的方式一个参数一个参数的接收会比较繁琐。
此时我们可以考虑将请求参数封装到一个实体类对象中。 要想完成数据封装需要遵守如下规则请求参数名与实体类的属性名相同
1.3.1 简单实体对象
定义POJO类
package com.yongzhi.springbootwebreqresp.pojo;public class User {private String name;private int age;private Address address;public User() {}public User(String name, int age, Address address) {this.name name;this.age age;this.address address;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}/*** 获取* return address*/public Address getAddress() {return address;}/*** 设置* param address*/public void setAddress(Address address) {this.address address;}public String toString() {return User{name name , age age , address address };}
}
Controller方法
RestController
public class RequestController {//实体参数简单实体对象RequestMapping(/simplePojo)public String simplePojo(User user){System.out.println(user);return OK;}
}这里需要指出当请求参数名中有和实体类属性名不一致的时候不会报错而是会自动将没有对应上的实体对象的参数赋值为默认值
1.3.2 复杂实体对象
复杂实体对象指的是在实体类中有一个或多个属性也是实体对象类型的。
复杂实体对象的封装需要遵守如下规则
请求参数名与形参对象属性名相同按照对象层次结构关系即可接收嵌套实体类属性参数。
定义POJO实体类
Address实体类
package com.yongzhi.springbootwebreqresp.pojo;public class Address {private String province;private String city;public Address() {}public Address(String province, String city) {this.province province;this.city city;}/*** 获取* return province*/public String getProvince() {return province;}/*** 设置* param province*/public void setProvince(String province) {this.province province;}/*** 获取* return city*/public String getCity() {return city;}/*** 设置* param city*/public void setCity(String city) {this.city city;}public String toString() {return Address{province province , city city };}
}User实体类
package com.yongzhi.springbootwebreqresp.pojo;public class User {private String name;private int age;private Address address;public User() {}public User(String name, int age, Address address) {this.name name;this.age age;this.address address;}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}/*** 获取* return age*/public int getAge() {return age;}/*** 设置* param age*/public void setAge(int age) {this.age age;}/*** 获取* return address*/public Address getAddress() {return address;}/*** 设置* param address*/public void setAddress(Address address) {this.address address;}public String toString() {return User{name name , age age , address address };}
}
Postman测试
1.4 数组集合参数
数组集合参数的使用场景在HTML的表单中有一个表单项是支持多选的(复选框)可以提交选择的多个值。 这多个值也是一个个提交的而后端接收这种数据有两种方式
数组集合
1.4.1 数组
数组参数请求参数名与形参数组名称相同且请求参数为多个定义数组类型形参即可接收参数 Controller方法
RestController
public class RequestController {//数组集合参数RequestMapping(/arrayParam)public String arrayParam(String[] hobby){System.out.println(Arrays.toString(hobby));return OK;}
}Postman测试
在前端请求时有两种传递形式
方式一 xxxxxxxxxx?hobbygamehobbyjava 方式二xxxxxxxxxxxxx?hobbygame,java
1.4.2 集合
集合参数请求参数名与形参集合对象名相同且请求参数为多个RequestParam 绑定参数关系 默认情况下请求中参数名相同的多个值是封装到数组。如果要封装到集合要使用RequestParam绑定参数关系 Controller方法 RestController
public class RequestController {//数组集合参数RequestMapping(/listParam)public String listParam(RequestParam ListString hobby){System.out.println(hobby);return OK;}
}1.5 日期参数
上述演示的都是一些普通的参数在一些特殊的需求中可能会涉及到日期类型数据的封装。
因为日期的格式多种多样如2022-12-12 10:05:45 、2022/12/12 10:05:45那么对于日期类型的参数在进行封装的时候需要通过DateTimeFormat注解以及其pattern属性来设置日期的格式。
DateTimeFormat注解的pattern属性中指定了哪种日期格式前端的日期参数就必须按照指定的格式传递。后端controller方法中需要使用Date类型或LocalDateTime类型来封装传递的参数。
Controller方法
RestController
public class RequestController {//日期时间参数RequestMapping(/dateParam)public String dateParam(DateTimeFormat(pattern yyyy-MM-dd HH:mm:ss) LocalDateTime updateTime){System.out.println(updateTime);return OK;}
}Postman测试
1.6 JSON参数
在前后端进行交互时如果是比较复杂的参数前后端通过会使用JSON格式的数据进行传输。 JSON是开发中最常用的前后端数据交互方式
学习JSON格式参数主要从以下两个方面着手 Postman在发送请求时如何传递json格式的请求参数 服务端Controller方法接收JSON格式数据 传递json格式的参数在Controller中会使用实体类进行封装。封装规则JSON数据键名与形参对象属性名相同定义POJO类型形参即可接收参数。需要使用 RequestBody标识。
RequestBody注解将JSON数据映射到形参的实体类对象中JSON中的key和实体类中的属性名保持一致
实体类Address
public class Address {private String province;private String city;//省略GET , SET 方法
}实体类User
public class User {private String name;private Integer age;private Address address;//省略GET , SET 方法
} Controller方法
RestController
public class RequestController {//JSON参数RequestMapping(/jsonParam)public String jsonParam(RequestBody User user){System.out.println(user);return OK;}
}1.7 路径参数
在现在的开发中经常还会直接在请求的URL中传递参数。例如
http://localhost:8080/user/1
http://localhost:880/user/1/0上述的这种传递请求参数的形式呢我们称之为路径参数。
路径参数
前端通过请求URL直接传递参数后端使用{…}来标识该路径参数需要使用PathVariable获取路径参数
Controller方法
RestController
public class RequestController {//路径参数RequestMapping(/path/{id})public String pathParam(PathVariable Integer id){System.out.println(id);return OK;}
}Postman测试
传递多个路径参数
Postman Controller方法
RestController
public class RequestController {//路径参数RequestMapping(/path/{id}/{name})public String pathParam2(PathVariable Integer id, PathVariable String name){System.out.println(id : name);return OK;}
}2 响应
2.1 ResponseBody注解
类型方法注解、类注解位置书写在Controller方法上或类上作用将方法返回值直接响应给浏览器 如果返回值类型是实体对象/集合将会转换为JSON格式后在响应给浏览器
需要指出的是在上面的代码中我们并没有添加ResponseBody注解但依然能够将结果响应给浏览器这是因为我们在类上添加的RestController注解是一个组合注解
RestController ResponseBody Controller
RestController源码
Target({ElementType.TYPE}) //元注解修饰注解的注解
Retention(RetentionPolicy.RUNTIME) //元注解
Documented //元注解
Controller
ResponseBody
public interface RestController {AliasFor(annotation Controller.class)String value() default ;
}故我们在类上添加了RestController注解就相当于添加了ResposeBody注解
小结 类上有RestController注解或ResponseBody注解时表示当前类下所有的方法返回值做为响应数据 方法的返回值如果是一个POJO对象或集合时会先转换为JSON格式在响应给浏览器
2.2 统一响应结果
对于前端开发人员来讲如果拿到响应数据但是没有统一的规范那么就需要针对不同的响应数据就要使用不同的响应方式这就会造成开发成本高项目不方便管理维护起来也会很困难所以我们就需要统一响应结果这样对于前端人员来说只需要按照统一格式的返回结果进行解析(仅一种解析方案)就可以拿到数据。 统一的返回结果使用类来描述在这个结果中包含 响应状态码当前请求是成功还是失败 状态码信息给页面的提示信息 返回的数据给前端响应的数据字符串、对象、集合
3 分层解耦
3.1 三层架构
3.1.1 介绍
在我们进行程序设计以及程序开发时尽可能让每一个接口、类、方法的职责更单一些单一职责原则。 单一职责原则一个类或一个方法就只做一件事情只管一块功能。 这样就可以让类、接口、方法的复杂度更低可读性更强扩展性更好也更利用后期的维护。 一般情况下我们会将业务分成三个部分
数据访问负责业务数据的维护操作包括增、删、改、查等操作。逻辑处理负责业务逻辑处理的代码。请求处理、响应数据负责接收页面的请求给页面响应数据。
按照上述的三个组成部分在我们项目开发中可以将代码分为三层
Controller控制层。接收前端发送的请求对请求进行处理并响应数据。Service业务逻辑层。处理具体的业务逻辑。Dao数据访问层(Data Access Object)也称为持久层。负责数据访问操作包括数据的增、删、改、查。
基于三层架构的程序执行流程
前端发起的请求由Controller层接收Controller响应数据给前端Controller层调用Service层来进行逻辑处理Service层处理完后把处理结果返回给Controller层Serivce层调用Dao层逻辑处理过程中需要用到的一些数据要从Dao层获取Dao层操作文件中的数据Dao拿到的数据会返回给Service层
这样按照三层架构的思想我们倘若要对业务逻辑Service层进行变更也不会影响到Controller层和Dao层这使得程序的扩展性和业务性变得更好了
总之三层架构的好处可以归纳为
复用性强便于维护利用扩展
3.2 分层解耦
上面我们说的是分层的思想接下来说一下解耦的思想所谓解耦就是接触耦合的意思
3.2.1 耦合问题
首先需要了解软件开发涉及到的两个概念内聚和耦合。 内聚软件中各个功能模块内部的功能联系。 耦合衡量软件中各个层/模块之间的依赖、关联的程度。
软件设计原则高内聚低耦合。 高内聚指的是一个模块中各个元素之间的联系的紧密程度如果各个元素(语句、程序段)之间的联系程度越高则内聚性越高即 “高内聚”。 低耦合指的是软件中各个层、模块之间的依赖关联程序越低越好。 高内聚、低耦合的目的是使程序模块的可重用性、移植性大大增强。
3.2.2 解耦思路
我们在使用一个类里面的方法时我们首先需要创建对应的对象然后调用对应的方法而我们要解耦首先就不能在其他类里面使用new对象但此时又会面临一个问题我们如果不new出对应的对象便不能在其他类里面使用对应的方法了那该怎么办呢 我们的解决思路是 提供一个容器容器中存储一些对象controller程序从容器中获取对应类型的对象
要实现上述解耦操作就涉及到Spring中的两个核心概念 控制反转 Inversion Of Control简称IOC。对象的创建控制权由程序自身转移到外部容器这种思想称为控制反转。 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为IOC容器或Spring容器 依赖注入 Dependency Injection简称DI。容器为应用程序提供运行时所依赖的资源称之为依赖注入。 程序运行时需要某个资源此时容器就为其提供这个资源。 例EmpController程序运行时需要EmpService对象Spring容器就为其提供并注入EmpService对象
IOC容器中创建、管理的对象称之为bean对象
3.3 IOCDI
3.3.1 bean对象声明
前面我们提到IOC控制反转就是将对象的控制权交给Spring的IOC容器由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。
在IOC容器中每一个Bean都有一个属于自己的名字可以通过注解的value属性指定bean的名字。如果没有指定默认为类名首字母小写。
注意事项:
声明bean的时候可以通过value属性指定bean的名字如果没有指定默认为类名首字母小写。使用以上四个注解都可以声明bean但是在springboot集成web开发中声明控制器bean只能用Controller。
3.3.2 IOC详解
当我们要把某个对象交给IOC容器管理需要在类上添加一个注解Component
而Spring框架为了更好的标识web应用程序开发当中bean对象到底归属于哪一层又提供了Component的衍生注解
Controller 标注在控制层类上Service 标注在业务层类上Repository 标注在数据访问层类上
要把某个对象交给IOC容器管理需要在对应的类上加上如下注解之一
注解说明位置ControllerComponent的衍生注解标注在控制器类上ServiceComponent的衍生注解标注在业务类上RepositoryComponent的衍生注解标注在数据访问类上由于与mybatis整合用的少Component声明bean的基础注解不属于以上三类时用此注解
组件扫描
当我们使用注解声明了一个bean后这个bean对象不一定会生效这是因为使用四大注解声明的bean要想生效还需要被组件扫描注解ComponentScan扫描 需要指出 ComponentScan注解虽然没有显式配置但是实际上已经包含在了引导类声明注解 SpringBootApplication 中默认扫描的范围是SpringBoot启动类所在包及其子包。
SpringBootApplication源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;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 {AliasFor(annotation EnableAutoConfiguration.class)Class?[] exclude() default {};AliasFor(annotation EnableAutoConfiguration.class)String[] excludeName() default {};AliasFor(annotation ComponentScan.class,attribute basePackages)String[] scanBasePackages() default {};AliasFor(annotation ComponentScan.class,attribute basePackageClasses)Class?[] scanBasePackageClasses() default {};AliasFor(annotation ComponentScan.class,attribute nameGenerator)Class? extends BeanNameGenerator nameGenerator() default BeanNameGenerator.class;AliasFor(annotation Configuration.class)boolean proxyBeanMethods() default true;
}
所以为了避免不必要的麻烦一般推荐的做法是
将我们定义的controllerservicedao这些包呢都放在引导类所在包com.itheima的子包下这样我们定义的bean就会被自动的扫描到
3.3.3 DI详解
依赖注入是指IOC容器要为应用程序去提供运行时所依赖的资源而资源指的就是对象。
我们可以使用Autowired这个注解完成依赖注入的操作而这个Autowired翻译过来叫自动装配。
Autowired注解默认是按照类型进行自动装配的去IOC容器中找某个类型的对象然后完成注入操作那么问题来了当IOC容器中存在多个相同类型的bean对象时进行组件扫描的时候就会区分不了该用那个bean对象从而报错。
为了解决上述问题Spring提供了三种解决方案 Primary 使用Primary注解当存在多个相同类型的Bean注入时加上Primary注解来确定默认的实现。 Qualifier 使用Qualifier注解指定当前要注入的bean对象。 在Qualifier的value属性中指定注入的bean的名称。 Qualifier注解不能单独使用必须配合Autowired使用 Resource
使用Resource注解是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。 面试题 Autowird 与 Resource的区别 Autowired 是spring框架提供的注解而Resource是JDK提供的注解Autowired 默认是按照类型注入而Resource是按照名称注入