之前我们讲过axios,那么我们直接运用,代码如下:
发现存在几个问题,
(1)请求url,http:localhost:9001 其实属于项目根路径,发送axios时没必要一直重复书写,
还存在一个问题就是不同环境的ip+端口不一致,我们在开发环境是http:localhost:9001,到了生产环境可能是http://10.1.1.1:7777等,那么我们不可能一直改所有axios请求的代码,所以要把根路径提取出来,分环境配置
(2)接口调不通
原因1:后台接口还没写
原因2:前端端口8080,后端端口9001,属于跨域问题
接下来一个一个解决这些问题
(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,再重启下。
此处,就不写后台项目搭建过程,只展示下登录接口的逻辑即可
先写个密码不加密,直接请求数据库的最简单的登录功能
使用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
}
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 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
}
数据库记录
用户名错误
密码错误
用户名为null
密码为null
登录成功
后台接口改成了/doLogin,在前端需要重新改下
页面登录,效果如下:
在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;
}
});
},
看下登录成功的效果
至此,简单的登录已经完成。
见我的博客
权限管理02-springboot整合springsecurity