转载

SpringBoot合理使用接口对业务代码和逻辑代码进行分离

未标准化进行java开发时,没有进行对业务代码以及公用逻辑进行分离,如果需求遇到改动,需要改公用逻辑时,需要去一处处业务代码中去找,大大的浪费了时间,使用接口后,可以合理的解决这一问题。

接口的概念

  • 使用interface声明的类
  • 只有方法标识符,没有方法体
  • 接口像蓝图一样,指明一个类必须要做什么和不能做什么
  • 接口中所有的方法都是抽象的和public的,所有的属性都是public,static,final的。
  • 一个类如果要实现某个接口时,必须要实现这个接口中的所有方法。

接口的作用

  • 实现多继承:因为Java不能像c++一样支持多继承,Java可以通过实现接口来弥补这个问题。
  • 接口可以解偶
  • 可以将逻辑代码与业务代码进行分

接口的语法

  • 使用interface声明一个类,在类内声明一个注册方法
public interface UserService {
    // 新用户注册接口
    public Integer AddUser(String userName,String userId,String password,String avatarSrc,String createTime);
}

复制代码
  • 创建接口实现类,使用Override重写AddUser方法
// 实现注册接口
    @Override
    public Integer AddUser(String userName, String userId, String password, String avatarSrc, String createTime) {
        User row = new User();
        row.setUserName(userName);
        row.setUserId(userId);
        row.setPassword(password);
        row.setAvatarSrc(avatarSrc);
        row.setCreateTime(createTime);
        // 增加用户,向数据库插入一条数据
        return userMapper.insertUser(row);
    }
复制代码

至此就就完成了一个接口的声明到实现

实际应用

我们先来看看不使用接口时,将功能的实现和业务代码全写在 controller 层的代码,这里我们以登录为例,如果遇到新的需求,我们就要去找找功能实现部分进行修改,业务代码过多时是一件很头疼的事情

@RestController
@RequestMapping("/user")
public class GreetingController {
    private final Logger logger= LoggerFactory.getLogger(getClass());
    @Resource
    private UserInfoMapper userMapper;
    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();
    @CrossOrigin()
    // 登录请求
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(@RequestBody String request){
        // 获取前端参数
        JSONObject jsReq = new JSONObject(request);
        JSONObject jsReply = new JSONObject();
        String username = jsReq.getString("username");
        String password = jsReq.getString("password");
        UserInfo row = new UserInfo();
        JSONArray queryType = new JSONArray();
        queryType.put("name");
        queryType.put("password");
        queryType.put("career");
        queryType.put("avatarSrc");
        queryType.put("userID");
        row.setQueryType(queryType);
        row.setName(username);
        List<UserInfo> resultList = userMapper.customQuery(row);
        JSONArray result = null;
        if(resultList.size()>0){
            result = new JSONArray(resultList);
            if(password.equals(result.getJSONObject(0).getString("password"))){
                jsReply.put("code",0);
                // 根据当前用户名和密码生成token
                jsReply.put("token", JwtUtil.sign(username,password));
                jsReply.put("msg","验证成功,token有效期为30分钟");
                jsReply.put("avatarSrc",result.getJSONObject(0).getString("avatarSrc"));
                jsReply.put("userID",result.getJSONObject(0).getString("userID"));
            }else{
                jsReply.put("code",-2);
                jsReply.put("msg","密码错误");
            }
        }else{
            jsReply.put("code",-1);
            jsReply.put("msg","当前登录用户不存在");
        }
        return jsReply.toString();
    }

}
复制代码
  • 使用接口对上述场景的代码进行分离(这里我们以注册功能为例)
// service层
package com.lk.service;

public interface UserService {
    // 新用户注册接口
    public Integer AddUser(String userName,String userId,String password,String avatarSrc,String createTime) throws Exception;
}


复制代码
// serviceimpl层(接口实现)
package com.lk.serviceimpl;

import com.lk.dao.UserMapper;
import com.lk.entity.User;
import com.lk.service.UserService;
import com.lk.utils.HMacMD5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;


@Service("userServiceImpl")
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
    private final Logger logger= LoggerFactory.getLogger(getClass());
    // 从配置文件读取加密key
    @Value("${HMacKey}")
    private String HMacKey;
    // 实现注册接口
    @Override
    public Integer AddUser(String userName, String userId, String password, String avatarSrc, String createTime) throws Exception {
        // 判断参数是否合法
        if(userName.equals("")||userName.length()>10){
            logger.error("违规操作:用户名为空或用户名长度大于10,"+userName);
            return -1;
        }else if(password.equals("")||password.length()>16){
            logger.error("违规操作:密码为空或密码长度大于10,"+password);
            return -2;
        }else if(avatarSrc.equals("")||avatarSrc.length()>300){
            logger.error("违规操作:头像地址为空或头像地址过长,"+avatarSrc);
            return -3;
        }
        // 对密码进行加密
        password = HMacMD5.encryptHMAC2String(password,HMacKey);
        User row = new User();
        row.setUserName(userName);
        row.setUserId(userId);
        row.setPassword(password);
        row.setAvatarSrc(avatarSrc);
        row.setCreateTime(createTime);
        logger.info(userMapper+"");
        // 增加用户,向数据库插入一条数据
        int result = userMapper.insertUser(row);
        logger.info(result+"");
        return result;
    }
}
复制代码
// controller层(业务代码)
package com.lk.controller;

import com.lk.dao.UserMapper;
import com.lk.serviceimpl.UserServiceImpl;
import com.lk.utils.DateUtil;
import com.lk.utils.UUIDUtil;
import com.lk.utils.UnifiedReturnDataUtil;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/api/user")
public class UserController {
    @Resource
    private UserMapper userMapper;
    @Resource(name = "userServiceImpl")
    private UserServiceImpl userService;
    private final Logger logger= LoggerFactory.getLogger(getClass());

    @RequestMapping(value = "/registered", method = RequestMethod.POST)
    public String login(@RequestBody String request) throws Exception {
        // 生成userId
        String userId = UUIDUtil.getUUID();
        // 生成注册日期
        String createTime = DateUtil.getThisTime();
        // 序列化前端参数
        JSONObject jsReq = new JSONObject(request);
        // 实例化注册服务
        // UserServiceImpl userService = new UserServiceImpl();
        // 调用注册接口
        int result = userService.AddUser(jsReq.getString("userName"),userId,jsReq.getString("password"),jsReq.getString("avatarSrc"),createTime);
        JSONArray responseData = new JSONArray();
        // 判断是否注册成功
        if(result>0){
            return UnifiedReturnDataUtil.returnJSONString(result,"注册成功",responseData);
        }
        return UnifiedReturnDataUtil.returnJSONString(result,"注册失败",responseData);
    }
}


复制代码

踩坑记录

在controller层使用接口实现类里的方法时,spring注解的内容一直为null,无法拿到@Resource注解的mybatis里的mapper对象和@Value注解的获取yml文件中的属性,接口实现类报空指针异常。 原因是:我在controller层实例化接口实现类时,对象是自己new的,没有走spring,所以一直为null。找了很多解决方案,走了很多弯路,最终使用@Service注解和@Resource注解完美解决了这个问题。 我的问题可以描述为:接口的实现类在controller层如何注入

  • 在controller层自己new接口实现类对象
// 错误的解决方案,实现类不走spring容器,报空指针异常
UserServiceImpl userService = new UserServiceImpl();
复制代码
  • 在接口实现类中使用@service注解,在controller层使用@Resource注入
// 这里括号中的名字为当前类名首字母小写
@Service("userServiceImpl")
public class UserServiceImpl implements UserService {
     /////++++++++++++++++++++++++/////
}
复制代码
// controller层
public class UserController {
    // 括号里的name值对应接口实现类@Service注解括号里的名字
    @Resource(name = "userServiceImpl")
    private UserServiceImpl userService;
}
复制代码

至此,关于接口实现类在controller层如何注入的问题就完美解决了,带大家看下上述注册接口实现的效果

SpringBoot合理使用接口对业务代码和逻辑代码进行分离
SpringBoot合理使用接口对业务代码和逻辑代码进行分离

写在最后

  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注:blush:
  • 本文首发于掘金,如需转载请评论区留言:love_letter:
原文  https://juejin.im/post/5e1fed4351882526945f46e2
正文到此结束
Loading...