【后端】初学Springboot项目

  • 一些学习的记录 未完待续

0. 参考视频

1. 前期准备+引入依赖

  • java的版本要选择自己软件的版本
    在这里插入图片描述
    依赖在这里插入图片描述
    在这里插入图片描述
1. 引入需要的依赖

在这里插入图片描述

  • 阿里云加速下载
 <repositories>
        <repository>
            <id>nexus-aliyun</id>
            <name>nexus-aliyun</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>aliyun nexus</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
2. 乱码解决
<exclude>
   <fork>true</fork>
    <!-- spring-boot:run 中文乱码解决 -->
    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
</exclude>
3. 数据库配置
  • application.yml 【yml格式】
server:
  port: 8091

spring:
  datasource:
    typr: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
    username: 数据库账户
    password: 数据库密码

#选择xml的路径
mybatis:
  mapper-locations: classpath:mapper/ *.xml

logging:
  level:
    com:
      example:
        mapper:
          debug

2. 测试

  1. 注意加上@Mapper和@Service
1. 网页查看user列表
@Autowired
    private UserService userService;
    @GetMapping("/list")
    public List<User> list(){
        return userService.list();
    }

2. apifox测试接口
测试
  • 前置URL末尾有斜杠 下面的URL就不用写

4. 代码逻辑

1. 其它代码
1. 需要在数据库中实现自动填充时间
  • MyBatis-Plus设置自动填充时间及@TableField(fill = FieldFill.INSERT)
  • 设置时间格式 @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”, timezone=“GMT+8”)
	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createtime;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime updatetime;
  • 在utils中设置自动填充类
package com.example.demo.utils;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * 默认值填充拦截器
 * @author fzg
 */
@Slf4j
@Component
public class FieldMetaObjectHandler implements MetaObjectHandler {
    /**新增时间**/
    private final String TIME_CREATE = "createtime";
    /**更新时间**/
    private final String TIME_UPDATE = "updatetime";

    /**
     * 新增默认填充器
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        //添加时间、最后更新时间
        System.out.println(metaObject);
        this.strictInsertFill(metaObject, TIME_CREATE, LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, TIME_UPDATE, LocalDateTime.class, LocalDateTime.now());
    }


    /**
     * 更新默认填充器
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        //最后更新时间
        this.strictInsertFill(metaObject, TIME_UPDATE, LocalDateTime.class, LocalDateTime.now());
    }
}
  • 或者/ 数据库直接填入字段
CURRENT_TIMESTAMP

在这里插入图片描述

5. springboot集成JWT

  • 程序员青戈视频
1. SpringBoot集成JWT实现token验证

SpringBoot集成JWT实现token验证

2. JWT依赖
        <!-- JWT -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>
  • TokenUtils
package com.qingge.springboot.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.qingge.springboot.entity.User;
import com.qingge.springboot.service.IUserService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Component
public class TokenUtils {

    private static IUserService staticUserService;

    @Resource
    private IUserService userService;

    @PostConstruct
    public void setUserService() {
        staticUserService = userService;
    }

    /**
     * 生成token
     *
     * @return
     */
    public static String genToken(String userId, String sign) {
        return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
        // offsetHour 即是小时
                .withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
    }

    /**
     * 获取当前登录的用户信息
     *
     * @return user对象
     */
    public static User getCurrentUser() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            // 获取token 解析信息
            String token = request.getHeader("token");
            if (StrUtil.isNotBlank(token)) {
                String userId = JWT.decode(token).getAudience().get(0);
                return staticUserService.getById(Integer.valueOf(userId));
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }
}

2. 设置token
  • 将密码加密后设置为token
  • 是在UserDTO中加的token
String token = TokenUtils.genToken(one.getId().toString(), one.getPassword());
userDTO.setToken(token);
3. token拦截器

在这里插入图片描述


public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private IUserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("token");

        // 如果不是映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        } else {
            HandlerMethod h = (HandlerMethod) handler;
            AuthAccess authAccess = h.getMethodAnnotation(AuthAccess.class);
            if (authAccess != null) {
                return true;
            }
        }
        // 执行认证
        if (StrUtil.isBlank(token)) {
            throw new ServiceException(Constants.CODE_401, "无token,请重新登录");
        }
        // 获取 token 中的 user id
        String userId;
        try {
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录");
        }
        // 根据token中的userid查询数据库
        User user = userService.getById(userId);
        if (user == null) {
            throw new ServiceException(Constants.CODE_401, "用户不存在,请重新登录");
        }
        // 用户密码加签验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token); // 验证token
        } catch (JWTVerificationException e) {
            throw new ServiceException(Constants.CODE_401, "token验证失败,请重新登录");
        }
        return true;
    }
}

4. 注册拦截器

在这里插入图片描述

6. 文件上传

  • 一些图片的上传
    在这里插入图片描述

在这里插入图片描述

  • 注意file后面还有一个反斜杠 不然图片会和file同一级
    在这里插入图片描述- FileController
  • 确保路径全英文,文件名不要有空格- 文件需要有一个后缀 不要用原始的文件名字
  • 存储的url在前台显示就可以点击下载
  • UUID是唯一的,所以相同的图片他的UUID也不一样
    // 把配置文件的路径赋予到这个变量中
    @Value("${files.upload.path}")
    private String fileUploadPath;

    /**
     * 文件上传接口
     * @param file 前端传递过来的文件
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String upload(@RequestParam MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        String type = FileUtil.extName(originalFilename);
        long size = file.getSize();

        // 定义一个文件唯一的标识码
        String fileUUID = IdUtil.fastSimpleUUID() + StrUtil.DOT + type;
		// 文件名字唯一 且拥有后缀
        **File uploadFile = new File(fileUploadPath + fileUUID);**
        // 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录
        File parentFile = uploadFile.getParentFile();
        if(!parentFile.exists()) {
            parentFile.mkdirs();
        }

// md5是从文件上获取的 可能相同的文件上获取到的md5也是同一个 这样只要想要添加的文件的md5已经存在了 就能知道是同一个文件
// 内容一样生成的md5就一样 所以区分是否相同文件靠的是MD5字段 而不是uuid uuid是为了防止磁盘文件名重复
        String url;
        // 获取文件的md5
        String md5 = SecureUtil.md5(file.getInputStream());
        // 从数据库查询是否存在相同的记录
        Files dbFiles = getFileByMd5(md5);
        if (dbFiles != null) {
            url = dbFiles.getUrl();
        } else {
            // 上传文件到磁盘
            file.transferTo(uploadFile);
            // 数据库若不存在重复文件,则不删除刚才上传的文件
            url = "http://" + serverIp + ":9090/file/" + fileUUID;
        }

        // 存储数据库
        Files saveFile = new Files();
        saveFile.setName(originalFilename);
        saveFile.setType(type);
        saveFile.setSize(size/1024); // 单位 kb
        saveFile.setUrl(url);
        saveFile.setMd5(md5);
        fileMapper.insert(saveFile);

        // 最简单的方式:直接清空缓存
        flushRedis(Constants.FILES_KEY);

        return url;
    }
  • 文件下载
   /**
     * 文件下载接口   http://localhost:9090/file/{fileUUID}
     * @param fileUUID
     * @param response
     * @throws IOException
     */
    @GetMapping("/{fileUUID}")
    public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
        // 根据文件的唯一标识码获取文件
        File uploadFile = new File(fileUploadPath + fileUUID);
        // 设置输出流的格式
        ServletOutputStream os = response.getOutputStream();
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
        response.setContentType("application/octet-stream");

        // 读取文件的字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

  • 查询这个文件是否已经存在
  • 如果已经存在就用同一个链接
    /**
     * 通过文件的md5查询文件
     * @param md5
     * @return
     */
    private Files getFileByMd5(String md5) {
        // 查询文件的md5是否存在
        QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("md5", md5);
        List<Files> filesList = fileMapper.selectList(queryWrapper);
        return filesList.size() == 0 ? null : filesList.get(0);
    }

1. 测试
  • 在一个请求前有另一个请求【POSTMAN使用】
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值