三层架构与MVC

​ 本文将对在JAVA中三层架构与MVC进行简单描述,并且阐述他们之间的联系与区别。

三层架构

​ 三层架构是目前B/S应用的主要应用框架,是将整个业务应用分为表现层/控制层Controller、业务逻辑层Service、持久层DAO,他们之间的关系如下图:

表现层:主要对于用户的请求进行接收,并且将接收到的请求数据传递给业务层进行处理,以及将业务层处理完成的结果进行返回,为客户端提供应用程序的访问。

业务逻辑层,简称业务层:主要对一些用户的请求进行数据、逻辑等业务的处理,并且将处理结果返回给表现层。

持久层DAO:主要是进行一些数据的持久化操作,简单来说就是我们需要根据业务层的要求对数据库等数据存储地进行访问,存储、查找、修改、删除数据

MVC框架

​ MVC全称又叫做Model View Controller。

  • Model指是我们的业务模型,其实也就是我们在后端的controller中给用户们返回的数据对象,这也是我们常说的VO对象(view object)

  • View指的是我们的视图也就是展现给用户的用户界面。

  • Controller指的是控制器,通过我们的业务模型来展示相应的界面给用户们。

​ 对于一些刚入门的新手来说,可能会有点混淆MVC框架与三层架构,就作者以前本科学校的时候很多刚入门的人他们都以为MVC就是三层架构。其实不是的,首先我们为了将应用进行解耦,为了提高某些业务逻辑的重用性,大牛们想出了三层架构实现了我们应用的高内聚低耦合。而MVC框架他只是三层架构中表现层的一个应用框架,比如三层架构是一个三层小楼房,第一层是DAO,第二层是我们的业务层,第三层是表现层,现在我们想装修这三层小楼房,那么MVC框架他就相当于一个工具协助我们更好的装修好我们的第三层楼。

​ 与MVC类似的还有我们DAO层的一些框架比如JOOQ、MyBatis、MyBatis-plus、Hibernate等框架,它们都相当于一个工具来协助我们更好的实线DAO层的一些功能。

三层架构与MVC框架在登录这个业务中的实战应用

下面我们基于登录这个业务需求来展示三层架构在我们后端的应用:

​ 首先在JAVA后端开发中我们会把三层架构,分成Controller(表现层),Service(业务逻辑层),DAO(持久层),同时也是以这三个包来划分成三层。如图:

表现层(Controller)

​ 在登录这个业务中,首先我们会在Controller层中接收到用户的登录请求,与用户的登录数据,

@RestController@RequestMapping("/AutoTest/User")public classUserController {@Autowiredprivate UserService userService;@ApiOperation(value = "用户登录接口",notes = "描述:用户登录的接口")@ApiImplicitParams({@ApiImplicitParam(name="User")})@PostMapping("/login")//user是用户发起登录这个请求传递过来的用户登录数据public ReturnResult login(@RequestBody User user){String token=null;//将用户的登录数据传递给业务逻辑层进行逻辑处理token = userService.login(user);JSONObject result = new JSONObject();//我们在拿到业务逻辑层的处理结果之后我们需要将数据进行统一封装然后返回,也就是我们上文中提到的VO对象/Model业务模型if(!token.equals(Constant.JWT_ERRCODE_FAIL+"")&&!token.equals(Constant.RESCODE_EXCEPTION+"")){user = userService.findUser(JwtUtil.getUser(token).getString("userId"));user.setPassword("XXXXX");result.put("userToken",token);result.put("user",user);//前端对拿到封装的数据进行判断,是否放行这个登录请求 //登录成功将用户的信息返回给前端,return ResultUtil.success(result, Constant.RESCODE_SUCCESS,1);}else{//登录失败return ResultUtil.error(Constant.JWT_ERRCODE_FAIL, "密码错误/账号不存在");}}

业务逻辑层(Service)

​ 在业务层中,我们对外提供的仅仅是他的接口,不暴露他的具体实现,也就是上面的UserService这个业务接口,

下面我们看业务逻辑层的具体实现UserServiceImp又是如何处理的,亦或是他又需要干什么:

@Service@Transactionalpublic class UserServiceImpextends ServiceImpl<UserDao, User> implements UserService {@Autowiredprivate UserDao userDao;@Autowiredprivate RedisTemplate redisTemplate;@Override//首先我们会收到由表现层传递过来的用户数据public String login(User user){String jwt = Constant.JWT_ERRCODE_FAIL+"";1.//设置DAO层访问参数QueryWrapper<User> queryWrapper = new QueryWrapper<>();1-1.//设置查询条件Map<String,Object> map = new HashMap<>(); if(user.getUserId().contains("@")){queryWrapper.allEq(map).and(qw->qw.eq("password", user.getPassword()).eq("email",user.getUserId()));}else {queryWrapper.allEq(map).and(qw->qw.eq("password", user.getPassword()).eq("userid",user.getUserId()));}//调用DAO层进行数据的查询/存储/删除/修改1-2.//这里我们需要查询这个用户的账号密码是否存在,也就是数据校验User u = userDao.selectOne(queryWrapper);2-1.//校验成功if (u!=null) {try {2-1-1.//将用户信息进行加密jwt = JwtUtil.createJWT(Constant.JWT_ID, JwtUtil.generalSubject(u), Constant.JWT_TTL);Claims claims = JwtUtil.parseJWT(jwt);System.out.println("添加注册本地token:");2-1-2.//把token(jwt)写入redisredisTemplate.opsForValue().set(user.getUserId(),jwt,Constant.JWT_TTL/1000, TimeUnit.SECONDS);return jwt;} catch (Exception e) {System.out.println("注册token出错:");System.out.println("异常代码:"+Constant.RESCODE_EXCEPTION);jwt = Constant.RESCODE_EXCEPTION+"";e.printStackTrace();}}2-2.//校验失败return jwt;}}

​ 在上述业务层代码中,我们进行了一系列的业务逻辑处理,首先我们拿到用户数据,我们会构造DAO参数然后进行数据库数据校验,在校验通过后我们会接着将用户数据进行加密生成token,然后将token写入redis最后将处理好的结果(我们生成的token)返回给表现层(Controller)进行下一步处理。

持久层(DAO)

​ 在持久层中,我们需要向业务逻辑层提供数据访问的接口。如上述业务层中,业务层需要校验用户这个登录数据即用户的账号密码是否正确,我们就需要向业务层提供一个可以通过账号和密码查询的接口:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();Map<String,Object> map = new HashMap<>(); if(user.getUserId().contains("@")){queryWrapper.allEq(map).and(qw->qw.eq("password", user.getPassword()).eq("email",user.getUserId()));}else {queryWrapper.allEq(map).and(qw->qw.eq("password", user.getPassword()).eq("userid",user.getUserId()));}User u = userDao.selectOne(queryWrapper);

​ 作者在这个项目中用的是MP(mybatis-plus)它这个框架已经给我们内置了我们当前登录业务需要的DAO接口。在实际中我们还需要提供各种各样的DAO接口,需要去编写我们mapper。比如: