网站悬挂备案号网站开发计划书

当前位置: 首页 > news >正文

网站悬挂备案号,网站开发计划书,网络服务顺序,陕西企业名录大全2. 响应 前面我们学习过HTTL协议的交互方式#xff1a;请求响应模式#xff08;有请求就有响应#xff09; 那么Controller程序呢#xff0c;除了接收请求外#xff0c;还可以进行响应。 2.1 ResponseBody 在我们前面所编写的controller方法中#xff0c;都已经设置了…2. 响应 前面我们学习过HTTL协议的交互方式请求响应模式有请求就有响应 那么Controller程序呢除了接收请求外还可以进行响应。 2.1 ResponseBody 在我们前面所编写的controller方法中都已经设置了响应数据。 controller方法中的return的结果怎么就可以响应给浏览器呢 答案使用ResponseBody注解 ResponseBody注解 类型方法注解、类注解位置书写在Controller方法上或类上作用将方法返回值直接响应给浏览器 如果返回值类型是实体对象/集合将会转换为JSON格式后在响应给浏览器 说明RestController Controller ResponseBody 但是在我们所书写的Controller中只在类上添加了RestController注解、方法添加了 RequestMapping注解并没有使用ResponseBody注解怎么给浏览器响应呢 RestController public class HelloController {RequestMapping(/hello)public String hello(){System.out.println(Hello World ~);return Hello World ~;} }原因在类上添加的RestController注解是一个组合注解。 RestController Controller ResponseBody RestController源码 Target({ElementType.TYPE}) //元注解修饰注解的注解 Retention(RetentionPolicy.RUNTIME) //元注解 Documented //元注解 Controller ResponseBody public interface RestController {AliasFor(annotation Controller.class)String value() default ; }结论在类上添加RestController就相当于添加了ResponseBody注解。 类上有RestController注解或ResponseBody注解时表示当前类下所有的方法返回值做为 响应数据 方法的返回值如果是一个POJO对象或集合时会先转换为JSON格式在响应给浏览器
下面我们来测试下响应数据 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 ListAddress listAddr(){ListAddress 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;} }在服务端响应了一个对象或者集合那私前端获取到的数据是什么样子的呢我们使用postman发送请求来测试下。测试效果如下
2.2 统一响应结果 我们在前面所编写的这些Controller方法中返回值各种各样没有任何的规范。
如果我们开发一个大型项目项目中controller方法将成千上万使用上述方式将造成整个项目难以 维护。那在真实的项目开发中是什么样子的呢 在真实的项目开发中无论是哪种方法我们都会定义一个统一的返回结果。方案如下 前端只需要按照统一格式的返回结果进行解析(仅一种解析方案)就可以拿到数据。 统一的返回结果使用类来描述在这个结果中包含 响应状态码当前请求是成功还是失败状态码信息给页面的提示信息返回的数据给前端响应的数据字符串、对象、集合 定义在一个实体类Result来包含以上信息。代码如下 public class Result {private Integer code;// 响应码1 代表成功; 0 代表失败private String msg; // 响应码 描述字符串private Object data; // 返回的数据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(){return new Result(1,success,null);}// 查询 成功响应(把查询结果做为返回数据响应给前端)public static Result success(Object data){return new Result(1,success,data);}// 失败响应public static Result error(String msg){return new Result(0, msg, null);} }改造Controller 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(){ListAddress 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);} }使用Apifox测试 2.3 案例 需求加载并解析xml文件中的数据完成数据处理并在页面展示
获取员工数据返回统一响应结果在页面渲染展示 2.3.2 准备工作 案例准备 XML文件 已经准备好(emp.xml)直接导入进来放在 src/main/resources目录下 工具类 已经准备好解析XML文件的工具类无需自己实现直接在创建一个包 com.itheima.utils 然后将工具类拷贝进来 前端页面资源 已经准备好直接拷贝进来放在src/main/resources下的static目录下
Springboot项目的静态资源(htmlcssjs等前端资源)默认存放目录为classpath:/static 、 classpath:/public、 classpath:/resources 在SpringBoot项目中静态资源默认可以存放的目录 · classpath:/static/ · classpath:/public/ · classpath:/resources/ · classpath:/META-INF/resources/ classpath · 代表的是类路径在maven的项目中其实指的就是 src/main/resources 或者 src/main/java但是java目录是存放java代码的所以相关的配置文件及静态资源文 档就放在 src/main/resources下。 2.3.3 实现步骤 在pom.xml文件中引入dom4j的依赖用于解析XML文件 dependencygroupIdorg.dom4j/groupIdartifactIddom4j/artifactIdversion2.1.3/version /dependency引入资料中提供的解析XML的工具类XMLParserUtils、实体类Emp、XML文件emp.xml 3. 引入资料中提供的静态页面文件放在resources下的static目录下 4. 创建EmpController类编写Controller程序处理请求响应数据
2.3.4 代码实现 Controller代码 package com.itheima.controller;import com.itheima.pojo.Emp; import com.itheima.pojo.Result; import com.itheima.utils.XmlParserUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.util.List;RestController public class EmpController {RequestMapping(/listEmp)public Result listEmp() {// 1、加载并解析xmlString file this.getClass().getClassLoader().getResource(emp.xml).getFile();System.out.println(file);ListEmp empList XmlParserUtils.parse(file, Emp.class);// 2、数据转换 gender、jobempList.stream().forEach((emp) - {// 处理gender 1男2“女String gender emp.getGender();if (1.equals(gender)) {emp.setGender(男);} else {emp.setGender(女);}// 处理job 1讲师2班主任3就业指导String job emp.getJob();if (1.equals(job)) {emp.setJob(讲师);} else if (2.equals(job)) {emp.setJob(班主任);} else {emp.setJob(就业指导);}});// 3、响应数据return Result.success(empList);} }统一返回结果实体类 package com.itheima.pojo;/*** 统一响应结果封装类*/ public class Result {private Integer code; // 响应码1 代表成功; 0 代表失败private String msg; // 响应码描述字符串private Object data; // 返回的数据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() {return new Result(1, success, null);}// 查询 成功响应(把查询结果做为返回数据响应给前端)public static Result success(Object data) {return new Result(1, success, data);}// 失败响应public static Result error(String msg) {return new Result(0, msg, null);}Overridepublic String toString() {return Result{ code code , msg msg \ , data data };} }2.3.5 测试 代码编写完毕之后我们就可以运行引导类启动服务进行测试了。 使用Apifox测试 打开浏览器在浏览器地址栏输入 http://localhost:8080/emp.html 2.3.6 问题分析 上述案例中解析XML数据获取数据的代码处理数据的逻辑的代码给页面响应的代码全部都堆积在一起了全部都写在controller方法中了。 当前程序的这个业务逻辑还是比较简单的如果业务逻辑再稍微复杂一点我们会看到Controller方 法的代码量就很大了。 当我们要修改操作数据部分的代码需要改动Controller当我们要完善逻辑处理部分的代码需要改动Controller当我们需要修改数据响应的代码还是需要改动Controller 这样呢就会造成我们整个工程代码的复用性比较差而且代码难以维护。 那如何解决这个问题呢 其实在现在的开发中有非常成熟的解决思路那就是分层开发。

  1. 分层解耦 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.1.2 代码拆分 我们使用三层架构思想来改造下之前的程序 控制层包名xxxx.controller业务逻辑层包名xxxx.service数据访问层包名xxxx.dao 3.1.2.1 控制层 控制层接收前端发送的请求对请求进行处理并响应数据 RestController public class EmpController {// 业务层对象private EmpService empService new EmpServiceA();RequestMapping(/listEmp)public Result list(){//1. 调用service层, 获取数据ListEmp empList empService.listEmp();//3. 响应数据return Result.success(empList);} }3.1.2.2 业务逻辑层 业务逻辑层处理具体的业务逻辑 业务接口 // 业务逻辑接口制定业务标准 public interface EmpService {// 获取员工列表public ListEmp listEmp(); }业务实现类 // 业务逻辑实现类按照业务标准实现 public class EmpServiceA implements EmpService {// dao层对象private EmpDao empDao new EmpDaoA();Overridepublic ListEmp listEmp() {// 1. 调用dao, 获取数据ListEmp empList empDao.listEmp();// 2. 对数据进行转换处理 - gender, jobempList.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(就业指导);}});return empList;} }3.1.2.3 数据访问层 数据访问层负责数据的访问操作包含数据的增、删、改、查 数据访问接口 // 数据访问层接口制定标准 public interface EmpDao {// 获取员工列表数据public ListEmp listEmp(); }数据访问实现类 // 数据访问实现类 public class EmpDaoA implements EmpDao {Overridepublic ListEmp listEmp() {// 1. 加载并解析emp.xmlString file this.getClass().getClassLoader().getResource(emp.xml).getFile();System.out.println(file);ListEmp empList XmlParserUtils.parse(file, Emp.class);return empList;} }三层架构的好处 复用性强便于维护利用扩展 3.2 分层解耦 刚才我们学习过程序分层思想了接下来呢我们来学习下程序的解耦思想。 解耦解除耦合。 3.2.1 耦合问题 首先需要了解软件开发涉及到的两个概念内聚和耦合。 内聚软件中各个功能模块内部的功能联系。耦合衡量软件中各个层/模块之间的依赖、关联的程度。 软件设计原则高内聚低耦合。 高内聚指的是一个模块中各个元素之间的联系的紧密程度如果各个元素(语句、程序段)之间 的联系程度越高则内聚性越高即 “高内聚”。 低耦合指的是软件中各个层、模块之间的依赖关联程序越低越好。 程序中高内聚的体现 EmpServiceA类中只编写了和员工相关的逻辑处理代码 程序中耦合代码的体现 把业务类变为EmpServiceB时需要修改controller层中的代码 高内聚、低耦合的目的是使程序模块的可重用性、移植性大大增强。
    3.2.2 解耦思路 之前我们在编写代码时需要什么对象就直接new一个就可以了。 这种做法呢层与层之间代码就耦合了当service层的实现变了之后 我们还需要修改controller层的代码。 那应该怎么解耦呢 首先不能在EmpController中使用new对象。代码如下 此时就存在另一个问题了不能new就意味着没有业务层对象程序运行就报错怎么办 呢 我们的解决思路是 提供一个容器容器中存储一些对象(例EmpService对象)controller程序从容器中获取EmpService类型的对象
    我们想要实现上述解耦操作就涉及到Spring中的两个核心概念 控制反转 Inversion Of Control简称IOC。对象的创建控制权由程序自身转移到外部 容器这种思想称为控制反转。 对象的创建权由程序员主动创建转移到容器(由容器创建、管理对象)。这个容器称为IOC 容器或Spring容器 依赖注入 Dependency Injection简称DI。容器为应用程序提供运行时所依赖的资源 称之为依赖注入。 程序运行时需要某个资源此时容器就为其提供这个资源。 例EmpController程序运行时需要EmpService对象Spring容器就为其提供并注入 EmpService对象 IOC容器中创建、管理的对象称之为bean对象 3.3 IOC控制反转DI依赖注入 上面我们引出了Spring中IOC和DI的基本概念下面我们就来具体学习下IOC和DI的代码实现。 3.3.1 IOCDI入门 任务完成Controller层、Service层、Dao层的代码解耦 思路 删除Controller层、Service层中new对象的代码Service层及Dao层的实现类交给IOC容器管理为Controller及Service注入运行时依赖的对象 Controller程序中注入依赖的Service层对象 Service程序中注入依赖的Dao层对象
    第1步删除Controller层、Service层中new对象的代码 第2步Service层及Dao层的实现类交给IOC容器管理 使用Spring提供的注解Component 就可以实现类交给IOC容器管理 第3步为Controller及Service注入运行时依赖的对象 使用Spring提供的注解Autowired 就可以实现程序运行时IOC容器自动注入需要的依赖对 象 完整的三层代码 Controller层 RestController public class EmpController {Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量private EmpService empService;RequestMapping(/listEmp)public Result listEmp() {// …ListEmp empList empService.listEmp();// 3、响应数据return Result.success(empList);} }Service层 Component //将当前对象交给IOC容器管理,成为IOC容器的bean public class EmpServiceB implements EmpService {Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量private EmpDao empDao;Overridepublic ListEmp listEmp() {ListEmp listEmp empDao.listEmp();// 数据转换 gender、joblistEmp.stream().forEach((emp) - {String gender emp.getGender();// gender 1男2女if (1.equals(gender)) {emp.setGender(男士);} else {emp.setGender(女士);}String job emp.getJob();// job 1: 讲师, 2: 班主任 , 3: 就业指导if (1.equals(job)) {emp.setJob(讲师);} else if (2.equals(job)) {emp.setJob(班主任);} else {emp.setJob(就业指导);}});return listEmp;} }Dao层 Component //将当前对象交给IOC容器管理,成为IOC容器的bean public class EmpDaoA implements EmpDao {Overridepublic ListEmp listEmp() {// 1. 加载并解析emp.xmlString file this.getClass().getClassLoader().getResource(emp.xml).getFile();System.out.println(file);ListEmp empList XmlParserUtils.parse(file, Emp.class);return empList;} }运行测试 启动SpringBoot引导类打开浏览器输入http://localhost:8080/emp.html 3.3.2 IOC详解 通过IOC和DI的入门程序呢我们已经基本了解了IOC和DI的基础操作。接下来呢我们学习下IOC控 制反转和DI依赖注入的细节。 3.3.2.1 bean的声明 前面我们提到IOC控制反转就是将对象的控制权交给Spring的IOC容器由IOC容器创建及管理对 象。IOC容器创建的对象称为bean对象。 在之前的入门案例中要把某个对象交给IOC容器管理需要在类上添加一个注解Component 而Spring框架为了更好的标识web应用程序开发当中bean对象到底归属于哪一层又提供了 Component的衍生注解 Controller 标注在控制层类上Service 标注在业务层类上Repository 标注在数据访问层类上 修改入门案例代码 Controller层 RestController //RestController Controller ResponseBody public class EmpController {Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量private EmpService empService;RequestMapping(/listEmp)public Result listEmp() {// 1、调用service, 获取数据ListEmp empList empService.listEmp();// 3、响应数据return Result.success(empList);} }Service层 //Component Service public class EmpServiceB implements EmpService {Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量private EmpDao empDao;Overridepublic ListEmp listEmp() {// 1. 调用dao, 获取数据ListEmp listEmp empDao.listEmp();// 2. 对数据进行转换处理 - gender, joblistEmp.stream().forEach((emp) - {String gender emp.getGender();// gender 1男2女if (1.equals(gender)) {emp.setGender(男士);} else {emp.setGender(女士);}String job emp.getJob();// job 1: 讲师, 2: 班主任 , 3: 就业指导if (1.equals(job)) {emp.setJob(讲师);} else if (2.equals(job)) {emp.setJob(班主任);} else {emp.setJob(就业指导);}});return listEmp;} }Dao层 //Component Repository public class EmpDaoA implements EmpDao {Overridepublic ListEmp listEmp() {// 1. 加载并解析emp.xmlString file this.getClass().getClassLoader().getResource(emp.xml).getFile();System.out.println(file);ListEmp empList XmlParserUtils.parse(file, Emp.class);return empList;} }要把某个对象交给IOC容器管理需要在对应的类上加上如下注解之一 注解说明位置ControllerComponent的衍生注解标注在控制器类上ServiceComponent的衍生注解标注在业务类上RepositoryComponent的衍生注解标注在数据访问类上由于与mybatis整合用的少Component声明bean的基础注解由于与mybatis整合用的少不属于以上三类时用此注解 查看源码 在IOC容器中每一个Bean都有一个属于自己的名字可以通过注解的value属性指定bean的名字。如果没有指定默认为类名首字母小写。 · 注意事项: 声明bean的时候可以通过value属性指定bean的名字如果没有指定默认为类名首字 母小写。 · 使用以上四个注解都可以声明bean但是在springboot集成web开发中声明控制器bean 只能用Controller。 3.3.2.2 组件扫描 问题使用前面学习的四个注解声明的bean一定会生效吗 答案不一定。原因bean想要生效还需要被组件扫描 下面我们通过修改项目工程的目录结构来测试bean对象是否生效 运行程序后报错 为什么没有找到bean对象呢 使用四大注解声明的bean要想生效还需要被组件扫描注解ComponentScan扫描 ComponentScan注解虽然没有显式配置但是实际上已经包含在了引导类声明注解 SpringBootApplication 中 默认扫描的范围是SpringBoot启动类所在包及其子包 。 解决方案手动添加ComponentScan注解指定要扫描的包 仅做了解不推荐 推荐做法如下图 将我们定义的controllerservicedao这些包呢都放在引导类所在包com.itheima的子 包下这样我们定义的bean就会被自动的扫描到 3.3.3 DI详解 上一小节我们讲解了控制反转IOC的细节接下来呢我们学习依赖注解DI的细节。 依赖注入是指IOC容器要为应用程序去提供运行时所依赖的资源而资源指的就是对象。 在入门程序案例中我们使用了Autowired这个注解完成了依赖注入的操作而这个Autowired翻 译过来叫自动装配。 Autowired注解默认是按照类型进行自动装配的去IOC容器中找某个类型的对象然后完成注入 操作 入门程序举例在EmpController运行的时候就要到IOC容器当中去查找EmpService这个类 型的对象而我们的IOC容器中刚好有一个EmpService这个类型的对象所以就找到了这个类型 的对象完成注入操作。 那如果在IOC容器中存在多个相同类型的bean对象会出现什么情况呢 程序运行会报错 如何解决上述问题呢Spring提供了以下几种解决方案 PrimaryQualifierResource 使用Primary注解当存在多个相同类型的Bean注入时加上Primary注解来确定默认的实现。 使用Qualifier注解指定当前要注入的bean对象。 在Qualifier的value属性中指定注入的 bean的名称。 Qualifier注解不能单独使用必须配合Autowired使用
    使用Resource注解是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。 面试题 Autowird 与 Resource的区别 Autowired 是spring框架提供的注解而Resource是JDK提供的注解 Autowired 默认是按照类型注入而Resource是按照名称注入 3.3.4小结