Erlo

SpringBoot+Vue3项目实战——SpringBoot篇

2024-09-01 11:29:16 发布   8 浏览  
页面报错/反馈
收藏 点赞

项目准备与配置

数据库以及其他项目配置

server:
  port: 9090

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/lostarknote
    username: root
    password: guxiang
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  configuration:
    map-underscore-to-camel-case: true

遇到问题:找不到"url"....
可能原因:没有扫描到配置文件(yml),在pom.xml中的build标签中添加以下内容


    
        src/main/java
        
            **/*.yml
            **/*.properties
            **/*.xml
        
        false
    
    
        src/main/resources
        
            **/*.yml
            **/*.properties
            **/*.xml
        
        false
    

启动类相关

@SpringBootApplication:包扫描时,自动扫描启动类所在包及其子包,若需要扫描其他包,需要使用@ComponentScan进行包名指定

Lombok工具:

自动生成getter/setter/toString方法 ,需要引入lombok依赖,然后在实体类上添加@Data注解


    org.projectlombok
    lombok
    1.18.30

Result实体类

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result {

    private Integer code;
    private String message;
    private T data;

    public static  Result success(E data)
    {
        return new Result(0,"操作成功",data);
    }

    public static Result success(){
        return new Result(0,"操作成功",null);
    }

    public static Result error(String message) {
        return new Result(1,message,null);
    }


}

用户模块

注册功能:

1.密码加密

public class MD5Util {
    //生成MD5
    public static String getMD5(String message) {
        String md5 = "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");  // 创建一个md5算法对象
            byte[] messageByte = message.getBytes("UTF-8");
            byte[] md5Byte = md.digest(messageByte);              // 获得MD5字节数组,16*8=128位
            md5 = bytesToHex(md5Byte);                            // 转换为16进制字符串
        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5;
    }

    // 二进制转十六进制
    public static String bytesToHex(byte[] bytes) {
        StringBuffer hexStr = new StringBuffer();
        int num;
        for (int i = 0; i 

2.参数校验——Spring Validation

image.png

3.全局异常处理器

@RestControllerAdvice
public class GobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e)
    {
        e.printStackTrace();
        return Result.error(StringUtils.hasLength(e.getMessage())? e.getMessage() : "操作失败!");
    }
}

登录功能

登录认证:JWT令牌

image.png
image.png

JWT工具类

public class JWTUtil {
    private static final String SECRET = "guxiang";

    public static String generateToken(Map claims){
        return JWT.create()
                .withClaim("claims", claims)
                .withExpiresAt(new Date(System.currentTimeMillis()* 1000 * 60 * 60 * 24))
                .sign(Algorithm.HMAC256(SECRET));
    }

    public static Map parseToken(String token){
        return JWT.require(Algorithm.HMAC256(SECRET))
                .build()
                .verify(token)
                .getClaim("claims")
                .asMap();
    }
}

JWT验证:从请求头中获取token

@RestController
@RequestMapping("/dungeon")
public class DungeonController {

    @GetMapping("/list")
    public Result list(@RequestHeader("Authorization") String token, HttpServletResponse response) {
        //验证token
        //若能正常解析(不报错),则验证通过
        try {
            Map claims = JWTUtil.parseToken(token);
            return Result.success("副本数据获取成功!");
        }catch (Exception e) {
            response.setStatus(401);
            return Result.error("未登录!");
        }

    }
}

进阶:注册拦截器进行验证。

注册一个拦截器进行token的验证,就不用单独在每个业务代码里进行token验证

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");

        //若能正常解析(不报错),则验证通过
        try {
            Map claims = JWTUtil.parseToken(token);
            //放行
            return true;
        }catch (Exception e) {
            response.setStatus(401);
            return false;
        }
    }
}
@Configuration
public class WebConfig  implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登录注册不用拦截
        registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
    }
}
@RestController
@RequestMapping("/dungeon")
public class DungeonController {

    @GetMapping("/list")
    public Result list() {
        //这里不用再验证token,已经统一在拦截器中做验证
        return Result.success("副本数据获取成功!");
    }
}

登录优化——Redis

image.png
image.png

获取用户信息

ThreadLocal

  • 获取用户信息需要通过token中存储的username到数据库中查找,需要解析token。
  • 在其他业务可能也需要username的信息,又要解析token,为了避免代码重复,在之前拦截器中解析出的token统一放到线程中(ThreadLocal)。

image.png

public class ThreadLocalUtil {

    //提供ThreadLocal对象
    private static final ThreadLocal THREAD_LOCAL= new ThreadLocal();

    public static  T get() {
        return (T) THREAD_LOCAL.get();
    }

    public static void set(Object value) {
        THREAD_LOCAL.set(value);
    }

    public static void remove() {
        THREAD_LOCAL.remove();
    }
}

拦截器中将数据存入ThreadLocal中,请求完成后清除ThreadLocal,防止内存泄露

@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //令牌验证
        String token = request.getHeader("Authorization");



        //若能正常解析(不报错),则验证通过
        try {
            Map claims = JWTUtil.parseToken(token);
            //将数据存储到ThreadLocal中
            ThreadLocalUtil.set(claims);
            //放行
            return true;
        }catch (Exception e) {
            response.setStatus(401);
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空ThreadLocal中的数据,防止内存泄露
        ThreadLocalUtil.remove();
    }
}

接口中从ThreadLocal中获取数据

@GetMapping("/userInfo")
    public Result userInfo(@RequestHeader("Authorization") String token) {
//        Map claims = JWTUtil.parseToken(token);
//        String username = (String) claims.get("username");

        Map map = ThreadLocalUtil.get();
        String username = (String) map.get("username");

        User loginUser = userService.findByUsername(username);

        return Result.success(loginUser);
    }

@JsonIgnore

image.png

更新用户信息

实体类中参数验证

image.png

更新用户密码

参数用一个map接收,因为接受的参数名与数据库中不一致
更新用户信息时,参数名与字段名一致,所以用user实体类接收
image.png

文章模块

新增文章分类

文章分类列表

@JsonFormat

image.png

文章分类详情

更新文章分类

image.png

新增文章

自定义校验

image.png

文章分页查询

image.png
image.png
image.png
image.png

文件上传

image.png


登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认