05 登录接口联调

1 前端发送axios,请求登录接口

之前我们讲过axios,那么我们直接运用,代码如下:

 在前端页面,进行登录,查看效果

发现存在几个问题,

(1)请求url,http:localhost:9001 其实属于项目根路径,发送axios时没必要一直重复书写,

还存在一个问题就是不同环境的ip+端口不一致,我们在开发环境是http:localhost:9001,到了生产环境可能是http://10.1.1.1:7777等,那么我们不可能一直改所有axios请求的代码,所以要把根路径提取出来,分环境配置

(2)接口调不通

       原因1:后台接口还没写

       原因2:前端端口8080,后端端口9001,属于跨域问题

接下来一个一个解决这些问题

2 配置axios请求的前缀

(1)设置我们的环境是development

NODE_ENV变量的值可以在package.json的script里改变,不填默认就是development

 在package.json中设置NODE_ENV

"serve": "set NODE_ENV=development&&vue-cli-service serve --port 8080"

修改,main.js,加入

// 配置项目根路径

if (process.env.NODE_ENV === 'development') {

  axios.defaults.baseURL = 'http://localhost:8080'

} else {

  axios.defaults.baseURL = 'http://10.0.0.1:9000'

}

 设置完之后,发送ajax请求就不用加上服务器前缀了

 再次在登录页面,请求登录接口,效果如下

 在package.json中把NODE_ENV设置为product,再请求接口(测试完把NODE_ENV改回development)

出问题了,难道是要重启前端项目?重启下再请求登录接口试下 

OK了,改了配置果然是要重启,记得把NODE_ENV改回development,再重启下。

 3 编写后台登录接口

此处,就不写后台项目搭建过程,只展示下登录接口的逻辑即可

先写个密码不加密,直接请求数据库的最简单的登录功能

(1)后台对参数进行校验(用户名,密码)

使用spring-boot-starter-validation依赖,怎么集成到springboot,可参考我的CSDN博客全局参数校验

package com.grm.entity;

import com.alibaba.fastjson.annotation.JSONField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.util.Date;

/**
 * 用户实体类
 *
 * @author gaorimao
 * @since 2021-12-04
 */
public class SysUser {
    private Long id;
    @NotEmpty
    @Pattern(regexp = "[A-Za-z]{6,10}", message = "格式错误")
    private String username;
    @NotEmpty
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,}", message = "格式错误")
    private String password;

    // getter setter toString
}

 (2)登录逻辑实现

import com.grm.common.Result;
import com.grm.entity.SysUser;
import com.grm.exception.BusinessException;
import com.grm.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.List;

@RestController
public class LoginController {
    private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
    @Autowired
    private SysUserService sysUserService;

    @PostMapping(value = "/doLogin", produces = "application/json;charset=UTF-8")
    public Result login(@RequestBody @Valid SysUser sysUser) {
        // 根据用户名查用户
        SysUser condition = new SysUser();
        condition.setUsername(sysUser.getUsername());
        List<SysUser> sysUsers = sysUserService.querySelective(condition);
        if (!CollectionUtils.isEmpty(sysUsers)) {
            SysUser dbSysUser = sysUsers.get(0);
            // 用户名+密码都正确,登录成功
            if (sysUser.getPassword().equals(dbSysUser.getPassword())) {
                return Result.success("登录成功!");
            } else {
                // 用户名正确,密码错误(提示不能太具体,防止攻击)
                throw new BusinessException(500, "用户名或密码错误!");
            }
        } else {
            // 用户名错误(提示不能太具体,防止攻击)
            throw new BusinessException(500, "用户名或密码错误!");
        }
    }
}

 mapper层,没加@mapper注解原因是在启动类配置了@MapperScan("com.grm.mapper")

  这里边的BusinessException是全局业务异常类,继承了RuntimeException

/**
 * 业务异常类
 *
 * @author gaorimao
 * @since 2021-12-26 18:38:37
 */
public class BusinessException extends RuntimeException {
    private int code;
    private String message;

    public BusinessException(int code, String message) {
        this.code = code;
        this.message = message;
    }

    // getter setter toString
}

 但是返回给前台是json,所以要使用全局异常捕获,来对参数校验失败和业务异常进行捕获,写一个GlobalExceptionHandler

import com.grm.common.Result;
import com.grm.exception.BusinessException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.StringJoiner;

/**
 * 自定义全局异常捕获
 *
 * @author gaorimao
 */
@RestControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandler {
    /**
     * 全局异常捕捉处理
     *
     * @param e 异常
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public Result errorHandler(HttpServletRequest req, Exception e) {
        return Result.failed(500, e.getMessage());
    }

    /**
     * 全局异常捕捉处理
     *
     * @param e 异常
     * @return
     */
    @ExceptionHandler(value = BusinessException.class)
    public Result businessExceptionHandler(HttpServletRequest req, Exception e) {
        return Result.failed(500, e.getMessage());
    }

    /**
     * post请求body体参数校验,异常
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result methodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 将所有的错误提示使用";"拼接起来并返回
        StringJoiner sj = new StringJoiner(";");
        //name:不能为空;password:长度不能小于4
        e.getBindingResult().getFieldErrors().forEach(x -> sj.add(x.getField()+":"+x.getDefaultMessage()));
        return Result.failed(500, sj.toString());
    }

    /**
     * 缺少body请求体异常处理器
     *
     * @param e 缺少请求体异常
     * @return ResponseResult
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        return Result.failed(500, "body请求体不能为空!");
    }

    /**
     * 忽略参数异常处理器
     *
     * @param e 忽略参数异常
     * @return ResponseResult
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
        return Result.failed(500, "请求参数"+e.getParameterName()+"不能为空!");
    }
}

 返回给前台的模板son,写个Result类即可

public class Result {
    private int code;
    private String message;
    private Object data;
    private Long count;

    private static int SUCCESS_CODE = 200;

    public Result(int code, String message, Object data, Long count) {
        this.code = code;
        this.message = message;
        this.data = data;
        this.count = count;
    }

    public static Result success(String message) {
        return new Result(SUCCESS_CODE, message, null, null);
    }

    public static Result success(String message, Object data) {
        return new Result(SUCCESS_CODE, message, data, null);
    }

    public static Result success(String message, Object data, Long count) {
        return new Result(SUCCESS_CODE, message, data, count);
    }

    public static Result failed(int code, String message) {
        return new Result(code, message, null, null);
    }

    // getter setter    

    // toString
}

(3)再用postman测试下登录

数据库记录

 用户名错误

密码错误

 用户名为空串 

用户名为null

 密码为空串

 密码为null

 登录成功

4 在前台调用登录接口

后台接口改成了/doLogin,在前端需要重新改下

页面登录,效果如下:

发现前台配置的根路径,端口写错了,应该是9001 

在main.js中改下,

再请求接口,发现出现CORS ERROR,说明跨域了,因为前台端口8080,后台端口9001

 跨域在后台代码中加一个配置即可,代码如下

package com.grm.config;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(false).maxAge(3600);
    }
}

 再登录,200了

 看下返回值

返回的不太正确,postman已经测试过后台了,肯定是前台传参的问题,看下

 {"params":{"username":"adminadmin","password":"aA1@assdwer"}}

 观察下,多了层params,改下前台代码

再试下,登陆成功!

 我们登录成功后,拿到登录接口的响应res,需要在前台添加路由跳转,跳转到后台主页去

那么,路由怎么跳转呢

// 去首页

this.$router.push('/index')

 完善前端登录代码

onSubmit(form) {
      this.$refs[form].validate((valid) => {
        if (valid) {
          this.$message({ message: "规则校验通过,去登陆!", type: "success" });
          this.$axios
            .post("/doLogin", {
              username: this.form.username,
              password: this.form.password,
            })
            .then((res) => {
              if(res.data.code == 200){
                // 去首页
                this.$router.push('/index')
              }else{
                console.log("res=========",res)
                this.$message.error(res.data.message);
              }
            });
        } else {
          return false;
        }
      });
    },

登录用户名或密码错误时,如下

 还是去掉规则校验通过的message提示吧,不然一个绿色提示,一个红色提示,怪怪的

完善后的代码如下

onSubmit(form) {
      this.$refs[form].validate((valid) => {
        if (valid) {
          this.$axios
            .post("/doLogin", {
              username: this.form.username,
              password: this.form.password,
            })
            .then((res) => {
              if(res.data.code == 200){
                this.$message({ message: "登录成功,去首页!", type: "success" });
                // 去首页
                this.$router.push('/index')
              }else{
                console.log("res=========",res)
                this.$message.error(res.data.message);
              }
            });
        } else {
          return false;
        }
      });
    },

看下登录成功的效果 

 至此,简单的登录已经完成。

5 基于security的登录实现(前后端分离)

见我的博客 

权限管理02-springboot整合springsecurity

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值