我们先来看一个请求响应类的代码,实现了从resource中读取user.txt文件获取用户信息封装,然后响应前端展示的功能。
package com.wzb.Controller;import cn.hutool.core.io.IoUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pojo.User;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** 用户信息Controller*/
@RestController
public class UserController {@RequestMapping("/list")public String list() {// 1.加载user.txt文件获取用户信息,并将每一行的信息封装到ArrayList集合中,一行信息就是一个字符串元素// 因为类和resource在编译之后是在一起的,所以说通过获得本类的类加载器,调用getResourceAsStream方法(参数就是需要的文件名)// 返回该文件的输入流,可以避免使用绝对路径获得文件的输入流InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");// 使用hutool中的IoUtil,便捷的读文件输入流的内容,需要指定编码,并返回一个集合,集合中的每一个元素就是文件的一行内容ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());// 2.解析集合,获取用户属性,将属性封装成用户再用集合收集List<User> userList = lines.stream().map(line -> {String[] parts = line.split(","); // 用","分割字符串,得到每一个属性Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);// 使用DateTimeFormatter类限定时间的格式,并按照该格式将String类型的时间字符串解析为LocalDateTime对象LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).collect(Collectors.toList());//3.响应数据// 使用hutool中的JSONUtil类,将集合解析为json字符串返回,还可以使用setDateFormat方法设置json的时间格式return JSONUtil.toJsonStr(userList, JSONConfig.create().setDateFormat("yyyy-MM-dd HH:mm:ss"));}
}
此时,这个代码已经可以实现业务功能了,但是其实还是可以进行优化的:因为进行响应、获取数据、逻辑处理都在一个类中完成,假如说业务逻辑稍微变化,那么需要修改的地方就太多了,维护起来十分困难,用专业的术语来讲就是高耦合。这并不符合软件设计的原则——“高类聚、低耦合”。所以说一般在企业开发中使用三层架构的方式来实现分层解耦,从而达到软件设计的原则,增强程序的复用性、可维护性。
三层架构
Controller直接接收浏览器发送的请求,并调用Service进行处理;Service调用Dao获取数据;Dao从数据库中获取数据返回给Service,Service对Dao返回的数据进行逻辑处理返回给Controller;最后Controller将处理好的数据响应给前端。项目中一般会有多个Controller、Service、Dao,所以说需要先定义好对应的接口,再按照对应的业务逻辑编写其实现类(面向接口编程)。
第一层:Controller(接收请求、响应数据)
Controller是控制层,主要职责是接收前端发送的请求,对请求进行处理,并给前端响应数据,这一层需要和Service关联。 通过三层架构修改代码,使得Controller中的代码只有接收请求和响应数据的功能:
package com.wzb.controller;import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.wzb.pojo.User;
import com.wzb.service.UserService;
import com.wzb.service.impl.UserServiceImpl;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
public class UserController {private final UserService userService = new UserServiceImpl();private final List<User> userList = userService.findUser();@RequestMapping("/list")public String list() {return JSONUtil.toJsonStr(userList, JSONConfig.create().setDateFormat("yyyy-MM-dd HH:mm:ss"));}}
第二层:Service(逻辑处理)
Service是业务逻辑层,主要的职责是处理具体的业务逻辑,这一层需要和Dao层关联;先在Dao层中获取了数据,再根据业务逻辑进行数据处理,将处理好的数据返回给Controller层。Service层的功能只有按照逻辑处理数据:
package com.wzb.service.impl;import com.wzb.dao.UserDao;
import com.wzb.dao.impl.UserDaoImpl;
import com.wzb.pojo.User;
import com.wzb.service.UserService;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;/*** Service层实现类**/
public class UserServiceImpl implements UserService {private final UserDao userDao = new UserDaoImpl();private final List<String> lines = userDao.findUser();public List<User> findUser() {List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).collect(Collectors.toList());return userList;}
}
第三层:Dao(数据访问)
Dao(Data Access Object 持久层),主要的职责是负责数据访问操作,包括数据的CRUD,这一层需要和数据库关联。Dao层在数据库中(或者其他数据源)获取数据之后,封装到集合中(或者不封装),直接返回到Service层,Service层进行处理。Dao层只负责和数据库交互获取数据。
package com.wzb.dao.impl;import cn.hutool.core.io.IoUtil;
import com.wzb.dao.UserDao;import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;/*** Dao层的实现类**/
public class UserDaoImpl implements UserDao {@Overridepublic List<String> findUser() {InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");return IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());}
}
这样通过三层架构,就将原来一个类中的代码、一个类实现的功能,分工给了三个类,这样每一层各司其职,代码的维护性、可复用性大大提高,也便于分层解耦。