springboot+vue项目之实现登录操作

一、登录逻辑分析

  登录的身份分为管理员和商家,管理员可以管理用户等信息,而商家只能管理自己的相关信息,如商品信息等。要实现不同的身份登录,使用简单工厂模式实现。简单工厂模式参考文章设计模式 | 简单工厂模式及典型应用 - 知乎 (zhihu.com)进行介绍学习。本项目中创建一个后端登录接口AdminLoginService.java,让管理员EmployeeService和商家MerchandiserService分别继承接口,对其中的方法分别进行实现。如下图所示:

图1-1 登录之简单工厂模式 

  Controller层接收前端发的请求,通过调用Service的方法,识别不同的身份,返回不同的数据,实现登录操作。

二、具体实现之基础准备

1、后台登录模型 LoginReq.java

@Getter
@Setter
@ApiModel(value = "后台登录模型")
public class LoginReq {
    @NotBlank(message = "账号不能为空")
    @ApiModelProperty(value = "账号",required = true)
    private String account;

    @NotBlank(message = "密码不能为空")
    @ApiModelProperty(value = "密码",required = true)
    private String password;

    @NotBlank(message = "验证码不能为空")
    @ApiModelProperty(value = "验证码",required = true)
    private String code;

    @NotBlank(message = "验证码令牌不能为空")
    @ApiModelProperty(value = "验证码令牌",required = true)
    private String uuid;

    @NotBlank(message = "账号类型不能为空")
    @ApiModelProperty(value = "账号类型(admin管理员,merchandiser商家)",required = true)
    private String type;
}

2、后台登录响应模型  AdminLoginResp.java

@Getter
@Setter
@ApiModel(value = "后台登录响应模型")
public class AdminLoginResp {
    @ApiModelProperty(value = "主键")
    private Long  id;

    @ApiModelProperty(value = "用户名")
    private String name;

    @ApiModelProperty(value = "头像")
    private String avatar;

    @ApiModelProperty(value = "权限(admin管理员,merchandiser商家)")
    private List<String> permissions;

    @ApiModelProperty(value = "令牌")
    private String uuid;

    @ApiModelProperty(value = "令牌过期时间")
    private Date expired;

    @ApiModelProperty(value = "是否超级管理员")
    private Long root;

    /**
     * 是否是管理员 JsonIgnore不要序列化,忽略该方法
     * @return
     */
    @JsonIgnore
    public boolean isAdmin(){
        return permissions.contains("admin");
    }
}

3、常量 MarketConstans.java

public interface MarketConstans {
     /**
     * 员工标识
     */
    String ADMIN="admin";

}

4、Redis常量  RedisConstans.java

public class RedisConstans {

    /**
     * 验证码的前缀
     */
    public static final String CAPTCHA_KEY="captcha:";

}

三、具体实现

1、Controller层

    通过前端发出的请求,注入AdminLoginService层,调用其中的方法,实现不同身份的登录。

权限的验证使用了Sa-Token,具体使用将在后续文章介绍。

@RestController
@RequestMapping(value = "/api")
@Api(tags = "后台-管理员和商家登录Api")
public class AdminLoginController {
    @Qualifier(value = "adminLoginServiceImpl")
    @Autowired
    private AdminLoginService adminLoginService;

    @ApiOperation(value = "登录")
    @PostMapping(value = "/login")
    public R<String> login(@RequestBody @Valid LoginReq req){
        //登录
        AdminLoginResp adminLoginResp = this.adminLoginService.login(req);
        //换令牌
        String token=null;
        //令牌有效期为1小时
        long one_hour=1000L*60*60;
        if (MarketConstans.ADMIN.equals(req.getType())){
            //管理员换令牌
            StpAdminUtil.login(adminLoginResp.getId(),one_hour);
            //获取令牌
            token=StpAdminUtil.getTokenValue();
        }else {
            //商家换令牌
            StpMerchandiserUtil.login(adminLoginResp.getId(),one_hour);
            //获取令牌
            token=StpMerchandiserUtil.getTokenValue();
        }
        return R.okHasData(token);
    }

    @SaAdminCheckLogin
    @ApiOperation(value = "管理员登录信息")
    @GetMapping(value = "/admin/info")
    public R<AdminLoginResp> adminInfo(){
        long userId = StpAdminUtil.getLoginIdAsLong();
        AdminLoginResp resp=this.adminLoginService.getUserInfo(userId,MarketConstans.ADMIN);
        return R.okHasData(resp);
    }

    @SaMerchandiserCheckLogin
    @ApiOperation(value = "商家登录信息")
    @GetMapping(value = "/merchandiser/info")
    public R<AdminLoginResp> merchandierInfo(){
        long userId = StpMerchandiserUtil.getLoginIdAsLong();
        AdminLoginResp resp=this.adminLoginService.getUserInfo(userId,MarketConstans.MERCHANDISER);
        return R.okHasData(resp);
    }

    @SaAdminCheckLogin
    @ApiOperation(value = "管理员登出")
    @PostMapping(value = "/admin/logout")
    public R adminLoginout(){
        StpAdminUtil.logout();
        return R.ok();
    }

    @SaMerchandiserCheckLogin
    @ApiOperation(value = "商家登出")
    @PostMapping(value = "/merchandiser/logout")
    public R merchandiserLogout(){
        StpMerchandiserUtil.logout();
        return R.ok();
    }
}

2、后端登录接口  AdminLoginService.java

public interface AdminLoginService {

    /**
     * 登录方法
     * @param req
     * @return
     */
    AdminLoginResp login(LoginReq req);

    /**
     * 根据id,类型获取信息
     * @param userId
     * @param type
     * @return
     */
    AdminLoginResp getUserInfo(long userId, String type);
}

 3、后台登录接口的具体实现 AdminLoginServiceImpl.java

@Service
public class AdminLoginServiceImpl implements AdminLoginService {
    /**
     * 管理员业务逻辑
     */
    @Autowired
    private EmployeeService employeeService;

    /**
     * 商家业务逻辑
     */
    @Autowired
    private MerchandiserService merchandiserService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public AdminLoginResp login(LoginReq req) {
        //验证 验证码有效性
        //得到redis的前缀
        String redisKey=RedisConstans.CAPTCHA_KEY+req.getUuid();
        //获取redis的值
        Object redisValue = this.redisTemplate.opsForValue().get(redisKey);
        //查看验证码的值是否存在
        if (Objects.isNull(redisValue)){
            throw new ServiceException(AckCode.CODE_NOT_FOUND);
        }
        //移除验证码
        this.redisTemplate.delete(redisKey);
        //验证码错误
        if (!req.getCode().equals(redisValue.toString())){
            throw  new ServiceException(AckCode.CODE_ERROR);
        }
        //简单工厂方法
        //管理员登录 or 商家登录
        if (req.getType().equals(MarketConstans.ADMIN)){
            return employeeService.login(req);
        }else if (req.getType().equals(MarketConstans.MERCHANDISER)){
            return merchandiserService.login(req);
        }else {
            throw new ServiceException(AckCode.SYSTEM_PARAM_FAIL);
        }
    }

    @Override
    public AdminLoginResp getUserInfo(long userId, String type) {
        if (type.equals(MarketConstans.ADMIN)){
            return employeeService.getUserInfo(userId,type);
        }else{
            return merchandiserService.getUserInfo(userId,type);
        }
    }
}

4、员工接口的实现 EmployeeServiceImpl.java

@Log4j2
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee>
    implements EmployeeService{
    @Override
    public AdminLoginResp login(LoginReq req) {
        //构造查询语句
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        //构建查询条件
        queryWrapper.eq(Employee::getLoginName,req.getAccount());
        //获取数据
        Employee db = this.getOne(queryWrapper);
        //判断数据是否为空
        if (Objects.isNull(db)){
            log.info(req.getAccount()+",不存在");
            throw new ServiceException(AckCode.USERNAME_PASSWORD_ERROR);
        }
        //判断密码是否正确checkpw(明文密码,密文密码)
        if (!BCrypt.checkpw(req.getPassword(),db.getLoginPwd())){
            log.info(req.getPassword()+",密码错误");
            throw new ServiceException(AckCode.USERNAME_PASSWORD_ERROR);
        }
        //判断状态是否已经被停用
        if (MarketConstans.DISABLE.equals(db.getStatus())){
            //1表示状态已经被停用
            log.info(req.getAccount()+",已经被停用");
            throw new ServiceException(AckCode.DEVICE_BANNED);
        }
        return getAdminLoginResp(db);


    }


    private AdminLoginResp getAdminLoginResp(Employee db) {
        //构造自定义对象
        AdminLoginResp resp = new AdminLoginResp();
        resp.setId(db.getId());
        resp.setName(db.getLoginName());
        resp.setAvatar(db.getAvatar());
        resp.setRoot(Long.parseLong(db.getRoot()));
        resp.setPermissions(Collections.singletonList(MarketConstans.ADMIN));
        return resp;
    }

    @Override
    public AdminLoginResp getUserInfo(long userId, String type) {
        Employee db = this.getById(userId);
        //自定义对象
        return getAdminLoginResp(db);
    }


}

5、商家接口的实现 MerchandiserServiceImpl.java

@Log4j2
@Service
public class MerchandiserServiceImpl extends ServiceImpl<MerchandiserMapper, Merchandiser>
    implements MerchandiserService{

    @Override
    public AdminLoginResp login(LoginReq req) {
        //构建查询语句
        LambdaQueryWrapper<Merchandiser> queryWrapper = new LambdaQueryWrapper<>();
        //构建查询条件
        queryWrapper.eq(Merchandiser::getLoginName,req.getAccount());
        //获取数据
        Merchandiser db = this.getOne(queryWrapper);
        //判断数据是否存在
        if (Objects.isNull(db)){
            //数据不存在
            log.info(req.getAccount()+",不存在");
            throw new ServiceException(AckCode.USERNAME_PASSWORD_ERROR);
        }
        //判断密码是否正确
        if (!BCrypt.checkpw(req.getPassword(),db.getLoginPwd())){
            log.info(req.getPassword()+",密码不正确");
            throw new ServiceException(AckCode.USERNAME_PASSWORD_ERROR);
        }
        //判断状态
        if (MarketConstans.ACCOUNT_UNAUDITED.equals(db.getStatus())){
            //如果等于0,则表示未被审核
            log.info(req.getAccount()+",商家状态还未审核");
            throw new ServiceException(AckCode.MERCHANDISER_ACCOUNT_NOT_VERIFIED);
        }else if (MarketConstans.ACCOUNT_REVIEW_FAILED.equals(db.getStatus())){
            //如果等于2,则表示审核未通过
            log.info(req.getAccount()+",未审核通过");
            throw new ServiceException(AckCode.MERCHANDISER_ACCOUNT_VERIFIED_FAILED);
        }
        //自定义对象
        return getAdminLoginResp(db);
    }

    private AdminLoginResp getAdminLoginResp(Merchandiser db) {
        AdminLoginResp resp = new AdminLoginResp();
        resp.setId(db.getId());
        resp.setName(db.getName());
        resp.setAvatar(db.getPicture());
        resp.setRoot(0L);
        resp.setPermissions(Collections.singletonList(MarketConstans.MERCHANDISER));

        return resp;
    }

    @Override
    public AdminLoginResp getUserInfo(long userId, String type) {
        Merchandiser db = this.getById(userId);
        //自定义对象
        return getAdminLoginResp(db);
    }

}

四、Swagger调试界面

  通过获取验证码,向后端发出请求,得到令牌,进行登录操作。

图4-1 swagger之管理员登录测试

图4-2 swagger之商家登录测试 

​​​​​​

  • 15
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
SpringBoot Vue项目是一种使用Vue.js作为前端框架,SpringBoot作为后端框架的项目开发方式。在这种项目中,前端使用Vue.js来处理用户界面和交互逻辑,后端使用SpringBoot来处理业务逻辑和数据传输。通过这样的方式,前端和后端可以相对独立地进行开发和部署,并通过API进行数据传输。 在具体实现上,可以通过以下步骤来创建一个SpringBoot Vue项目: 1. 创建一个SpringBoot项目:可以使用Spring Initializr来创建一个基本的SpringBoot项目,选择所需的依赖和配置。 2. 创建前端项目:可以使用Vue CLI来创建一个基本的Vue.js项目,配置相关的开发环境和依赖。 3. 配置前后端通信:在前端项目中,可以使用axios等工具来与后端进行数据交互,发送HTTP请求获取数据。在后端项目中,可以通过编写RESTful API来提供数据给前端。 4. 开发前后端功能:根据项目需求,前端可以开发用户界面、表单验证、数据展示等功能,后端可以开发业务逻辑、数据库操作、数据处理等功能。 5. 打包和部署:前端项目可以通过npm run build命令将代码打包成静态文件,然后将这些文件放入后端项目的静态资源目录中。后端项目可以通过打包成可执行的JAR文件或者WAR文件来部署到服务器上。 通过以上步骤,就可以创建一个基于SpringBootVue.js的项目,并实现前后端的协同开发和交互。希望这些信息对你有所帮助。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [教你如何制作vue+springboot项目](https://blog.csdn.net/xc9711/article/details/121725216)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值