SpringBoot项目实战

Token

基本详情

令牌(Token):在计算机领域,令牌是一种代表某种访问权限或身份认证信息的令牌。它可以是一串随机生成的字符或数字,用于验证用户的身份或授权用户对特定资源的访问。普通的令牌可能以各种形式出现,如访问令牌、身份令牌、刷新令牌等。

简单理解 : 每个用户生成的唯一字符串标识,可以进行用户识别和校验

类似技术:  天王盖地虎 ,小鸡炖蘑菇

优势: token验证标识无法直接识别用户的信息,盗取token后也无法`登录`程序! 相对安全!

个人理解:客户端将用户的账户密码发送过来,后端接收,并用token生成一个密钥

,后端可以设定token密钥的有效时间,过期无法使用。

前端登入成功后,需要在服务器获取数据,服务器对每一次请求都需要来验证是哪个用户擦发送的,我们就需要多次查询数据库,这样不断查询造成不小的压力,

所以,可以在客户端第一次发送账户密码的时候,用token传递给前端一个密钥,之后前端就可以传递这个密钥来登入,在密钥有效期内,无需查询数据库

jwt

Token是一项规范和标准(接口)

JWT(JSON Web Token)是具体可以生成,校验,解析等动作Token的技术(实现类)

 jwt工作流程
    - 用户提供其凭据(通常是用户名和密码)进行身份验证。
    - 服务器对这些凭据进行验证,并在验证成功后创建一个JWT。
    - 服务器将JWT发送给客户端,并客户端在后续的请求中将JWT附加在请求头或参数中。
    - 服务器接收到请求后,验证JWT的签名和有效性,并根据JWT中的声明进行身份验证和授权操作

jwt数据组成和包含信息

JWT由三部分组成: header(头部).payload(载荷).signature(签名)

我们需要理解的是, jwt可以携带很多信息! 一般情况,需要加入:有效时间,签名秘钥,其他用户标识信息!

有效时间为了保证token的时效性,过期可以重新登录获取!

签名秘钥为了防止其他人随意解析和校验token数据!

用户信息为了我们自己解析的时候,知道Token对应的具体用户!

如何使用

导入jwt依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>

 application.yaml

#jwt配置
jwt:
  token:
    tokenExpiration: 120 #有效时间,单位分钟
    tokenSignKey: headline123456  #当前程序签名秘钥 自定义

 封装jwt技术工具类(需要的时候复制)

package com.atguigu.utils;

import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.Date;

@Data
@Component
@ConfigurationProperties(prefix = "jwt.token")
public class JwtHelper {

    private  long tokenExpiration; //有效时间,单位毫秒 1000毫秒 == 1秒
    private  String tokenSignKey;  //当前程序签名秘钥

    //生成token字符串
    public  String createToken(Long userId) {
        System.out.println("tokenExpiration = " + tokenExpiration);
        System.out.println("tokenSignKey = " + tokenSignKey);
        String token = Jwts.builder()

                .setSubject("YYGH-USER")
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration*1000*60)) //单位分钟
                .claim("userId", userId)
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }

    //从token字符串获取userid
    public  Long getUserId(String token) {
        if(StringUtils.isEmpty(token)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        Integer userId = (Integer)claims.get("userId");
        return userId.longValue();
    }



    //判断token是否有效
    public  boolean isExpiration(String token){
        try {
            boolean isExpire = Jwts.parser()
                    .setSigningKey(tokenSignKey)
                    .parseClaimsJws(token)
                    .getBody()
                    .getExpiration().before(new Date());
            //没有过期,有效,返回false
            return isExpire;
        }catch(Exception e) {
            //过期出现异常,返回true
            return true;
        }
    }
}

测试

flase是未过期

true是过期

    @Test
    public void testToken() {
        //生成 传入用户标识
        String token = jwtHelper.createToken(1L);
        System.out.println("token 加密后的密钥= " + token);

        //解析用户标识
        int userId = jwtHelper.getUserId(token).intValue();
        System.out.println("userId 解析密钥得到的 = " + userId);

        //校验是否到期! false 未到期 true到期
        boolean expiration = jwtHelper.isExpiration(token);
        System.out.println("expiration是否过期 = " + expiration);
    }

项目一:微头条

项目结构

数据库

news_headline表

news_type表

news_user表

步骤一:项目部署

1.1创建项目,并导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--父工程-->
    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.0.5</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>springboot-project2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--web启动-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--快速启动-->
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter</artifactId>-->
<!--        </dependency>-->
        <!--事务,jdbc等启动-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!--druid启动-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-3-starter</artifactId>
            <version>1.2.20</version>
        </dependency>
        <!--mybatis plus 启动-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>

        <!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>

    </dependencies>

    <!--打包-->
    <build>
        <plugins>
            <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

1.2编写配置文件

application-source.yml

#数据源
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/sm_db?useUnicode=true
      username: root
      password: 123456

#mybatis plus
mybatis-plus:
  configuration:
    auto-mapping-unknown-column-behavior: failing  #自动注入
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #日志输出
    map-underscore-to-camel-case: true           #驼峰
  global-config:
    db-config:
      table-prefix: news_              # 配置MyBatis-Plus操作表的默认前缀
      id-type: auto                   # 全局主键的自增策略
      logic-delete-field: isDeleted        #全局指定逻辑删除
      logic-delete-value: 1         #逻辑已删除是1
      logic-not-delete-value: 0     #逻辑未删除是0
  mapper-locations: classpath:/mapper/*.xml
  type-aliases-package: com.example.pojo

application.yml

#导入
spring:
  profiles:
    active: source
#设置端口号的请求头
server:
  port: 8080
  servlet:
    context-path: /

#jwt配置
jwt:
  token:
    tokenExpiration: 120 #有效时间,单位分钟
    tokenSignKey: headline123456  #当前程序签名秘钥 自定义

1.3用 mybatis X 自动生成实体类,service层,mapper层

注意:给自动生成的实体类层的主键属性上加@TableId,版本号属性上加@Version

1.4启动类

@SpringBootApplication
@MapperScan("org.example.mapper")
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //分页插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());  //乐观锁
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());//防止全表更新删除插件
        return interceptor;
    }
}

步骤二:工具类

json响应

package org.example.json;

public class Result <T>{
    private  Integer code;
    private String message;
    private T data;
    public Result(){}

    public static <T>  Result<T>build(T body){
        Result result = new Result();
        result.setData(body);
        return  result;
    }

    public static <T> Result<T> build(T body,ResultEnum resultEnum){
        Result<T> result = build(body);
        result.setCode(resultEnum.getCode());
        result.setMessage(resultEnum.getMessage());
        return result;
    }

    public static <T> Result<T> ok(T body){
        Result<T> result = build(body);
        result.setCode(ResultEnum.SUCCESS.getCode());
        result.setMessage(ResultEnum.SUCCESS.getMessage());
        return  result;
    }




    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", data=" + data +
                '}';
    }
}
package org.example.json;

public enum ResultEnum {
    SUCCESS(200, "成功"),
    ERROR(500, "失败"),
    PARAM_ERROR(400, "参数错误"),
    NOT_FOUND(404, "未找到"),
    NOT_LOGIN(401, "未登录"),
    FORBIDDEN(403, "禁止访问"),
    DUPLICATE_KEY(500, "数据库中已存在该记录"),
    NOT_AUTH(403, "没有权限"),
    NOT_EXIST(404, "不存在"),
    NOT_MATCH(403, "不匹配"),
    NOT_PERMISSION(403, "没有权限"),
    NOT_VALID(400, "无效"),
    YHMCW(501, "用户名有误"),
    MMYW(503, "密码有误"),
    TOken(504,"notLogin"),
    YHM(505,"用户名被占用"),
    ;

    private Integer code;
    private String message;

    ResultEnum() {
    }

    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

MD5加密

public class MD5Util {
    public static String encrypt(String strSrc) {
        try {
            char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
                    '9', 'a', 'b', 'c', 'd', 'e', 'f' };
            byte[] bytes = strSrc.getBytes();  //使用平台的默认字符集将此 String 编码为 byte 序列,并 将结果存储到一个新的 byte 数组中。
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(bytes);
            bytes = md.digest();
            int j = bytes.length;
            char[] chars = new char[j * 2];
            int k = 0;
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                chars[k++] = hexChars[b >>> 4 & 0xf];
                chars[k++] = hexChars[b & 0xf];
            }
            return new String(chars);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException("MD5加密出错");
        }

    }

}

token令牌

这里给它加入到ioc容器中,方便引入前面我们在配置文件中给token定义的有效时间和签名密钥。

后续通过@Autowired来使用

不用@Autowired,用new的话,配置文件给他定义的就不生效了

    @Test
    public void test2() {
        JwtHelper jwtHelper = new JwtHelper();
        System.out.println("有效时间"+jwtHelper.getTokenExpiration());
        System.out.println("当前签名密码"+jwtHelper.getTokenSignKey());
    }

@Data
@Component
@ConfigurationProperties(prefix = "jwt.token")
public class JwtHelper {

    private  long tokenExpiration; //有效时间,单位毫秒 1000毫秒 == 1秒
    private  String tokenSignKey;  //当前程序签名秘钥

    //生成token字符串
    public  String createToken(Long userId) {
        System.out.println("tokenExpiration = " + tokenExpiration);
        System.out.println("tokenSignKey = " + tokenSignKey);
        String token = Jwts.builder()

                .setSubject("YYGH-USER")
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration*1000*60)) //单位分钟
                .claim("userId", userId)
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }

    //从token字符串获取userid
    public  Long getUserId(String token) {
        if(StringUtils.isEmpty(token)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        Integer userId = (Integer)claims.get("userId");
        return userId.longValue();
    }




    //判断token是否有效
    public  boolean isExpiration(String token){
        try {
            boolean isExpire = Jwts.parser()
                    .setSigningKey(tokenSignKey)
                    .parseClaimsJws(token)
                    .getBody()
                    .getExpiration().before(new Date());
            //没有过期,有效,返回false
            return isExpire;
        }catch(Exception e) {
            //过期出现异常,返回true
            return true;
        }
    }
}

步骤三:后台开发

用户模块开发

用户在客户端输入用户名密码并向后端提交,后端根据用户名和密码判断登录是否成功,用户有误或者密码有误响应不同的提示信息!

controller


/*获取token*/
    @PostMapping("login")
    public Result login(@RequestBody User user){
        Result result = userService.login(user);
        System.out.println(result);
        return result;
    }

service

    @Override
    public Result login(User user) {
        Result result = null;
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        //设置查询条件, 这里设置的是名字相同,因为密码前端传过来的是明文密码,所以这里先不做比较
        wrapper.eq(User::getUsername, user.getUsername());
        User user1 = userMapper.selectOne(wrapper);
        if (user1 == null) {
            result = Result.build(null, ResultEnum.YHMCW);
        } else {
            if (!(MD5Util.encrypt(user.getUserPwd()).equals(user1.getUserPwd()))) {
                result = Result.build(null, ResultEnum.MMYW);
            } else {
                String token = jwtHelper.createToken(Long.valueOf(user1.getUid()));
                HashMap<String, String> map = new HashMap<>();
                map.put("token", token);
                result = Result.ok(map);
            }
        }
        return result;
    }

客户端发送请求,提交token请求头,后端根据token请求头获取登录用户的详细信息并响应给客户端进行存储

 

controller

  /*登入*/
    @GetMapping("getUserInfo")
    public Result getUserInfo(@RequestHeader String token){
        Result userInfo = userService.getUserInfo(token);
        return userInfo;
    }

service

    @Override
    public Result getUserInfo(String token) {
        Result result;

        if (jwtHelper.isExpiration(token)) {
            //true是过期
            return result = Result.build(null, ResultEnum.TOken);
        }

        int id = jwtHelper.getUserId(token).intValue();
        User user = userMapper.selectById(id);

        if (user == null) {
            return result = Result.build(null, ResultEnum.TOken);
        }
        user.setUserPwd("");
        HashMap<String, User> map = new HashMap<>();
        map.put("loginUser", user);

        result = Result.ok(map);


        return result;
    }

用户在注册时输入用户名时,立刻将用户名发送给后端,后端根据用户名查询用户名是否可用并做出响应

 

controller

  //检查用户名是否可用/**/
    @PostMapping("checkUserName")
    public Result checkUserName(@RequestParam("username") String name){
        Result result = userService.checkUserName(name);
        return result;
    }

service

    @Override
    public Result checkUserName(String username) {
        Result result=null;
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,username);
        User user = userMapper.selectOne(wrapper);
        if(user!=null){
            return Result.build(null,ResultEnum.YHM);
        }else {
            return Result.ok(null);
        }
    }

客户端将新用户信息发送给服务端,服务端将新用户存入数据库,存入之前做用户名是否被占用校验,校验通过响应成功提示,否则响应失败提示

 

controller

   //注册
        @PostMapping("regist")
        public Result regist( @RequestBody User user){

            Result regist = userService.regist(user);
            return regist;
        }

service

   @Override
    public Result regist(User user) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,user.getUsername());
        Long l = userMapper.selectCount(wrapper);
        if(l>0){
         return    Result.build(null,ResultEnum.YHM);
        }
        //密码MD5加密
        user.setUserPwd(MD5Util.encrypt(user.getUserPwd()));
        int insert = userMapper.insert(user);
          return   Result.ok(null);
    }

首页模块开发

进入新闻首页,查询所有分类并动态展示新闻类别栏位

 

controller

  //进入新闻首页,查询所有分类并动态展示新闻类别栏位
    @GetMapping("findAllTypes")
    public Result findAllTypes(){
        return typeService.findAllTypes();
    }

 service

    @Override
    public Result findAllTypes() {
        List<Type> types = typeMapper.selectList(null);
       return Result.ok(types);
    }

- 客户端向服务端发送查询关键字,新闻类别,页码数,页大小
- 服务端根据条件搜索分页信息,返回含页码数,页大小,总页数,总记录数,当前页数据等信息,并根据时间降序,浏览量降序排序

 

因为请求体中的这几个数据,我们并没有来接收他们的类,所以这里可以定义一个用来接收客户端发送来的数据的类

@Data
public class PageVo {
    private String keyWords;
    private Integer type;
    private Integer pageNum;
    private Integer pageSize;

}

controller

    /*分页查询首页头条信息*/
    @PostMapping("findNewsPage")
    public Result findNewsPage(@RequestBody PageVo  pageVo){
    Result result=    headlineService.selectMyPage(pageVo);
    return result;
    }

service

   @Override
    public Result selectMyPage(PageVo pageVo) {
           Result result = null;
        // 分页查询
        IPage<Headline> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
          headlineMapper.selectMyPage(page, pageVo);
        //分页数据封装
        Map<String,Object> pageInfo =new HashMap<>();
        pageInfo.put("pageData",page.getRecords());
        pageInfo.put("pageNum",page.getCurrent());
        pageInfo.put("pageSize",page.getSize());
        pageInfo.put("totalPage",page.getPages());
        pageInfo.put("totalSize",page.getTotal());

        Map<String,Object> pageInfoMap=new HashMap<>();
        pageInfoMap.put("pageInfo",pageInfo);
        // 响应JSON
        return Result.ok(pageInfoMap);
    }

因为是多表联查, mybatis plus没有这样的方法,所以这个时候需要我们自己编写sql语句

 mapper

 IPage<Map> selectMyPage(IPage<Headline> page, @Param("portalVo")PageVo portalVo);

mapper.xml

    <select id="selectMyPage" resultType="map">
        select hid,title,type,page_views pageViews,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,
        publisher from news_headline where is_deleted=0
        <if test="portalVo.keyWords !=null and portalVo.keyWords.length()>0 ">
            and title like concat('%',#{portalVo.keyWords},'%')
        </if>
        <if test="portalVo.type != null and portalVo.type != 0">
            and type = #{portalVo.type}
        </if>
    </select>

- 用户点击"查看全文"时,向服务端发送新闻id
- 后端根据新闻id查询完整新闻文章信息并返回
- 后端要同时让新闻的浏览量+1

 

controller

    @PostMapping("showHeadlineDetail")
    public Result showHeadlineDetail(@RequestParam int   hid){
        return headlineService.showHeadlineDetail(hid);

    }

 service

    @Override
    public Result showHeadlineDetail(int hid) {
        Map map = headlineMapper.showHeadlineDetail(hid);
        Headline headline = new Headline();
        headline.setHid(hid);
       // headline.setVersion((Integer) map.get("version")); //设置版本  因每次修改都会更新版本
        headline.setPageViews((Integer) map.get("pageViews")+1); //阅读量+1
        headlineMapper.updateById(headline);

        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("headline", map);
        return Result.ok(hashMap);
    }

这里同样是多表,需要我们自己定义sql语句

mapper

    Map     showHeadlineDetail(@Param("hid") int hid);

mapper.xml

    <select id="showHeadlineDetail" resultType="java.util.Map">
        select hid,title,article,type,tname typeName,page_views pageViews, timestampdiff(hour ,create_time,now()) pastHours,
        publisher,nick_name author  from news_headline head left join news_type newst
        on type=newst.tid left join news_user user on publisher=user.uid
        where hid=#{hid}


    </select>

头条模块开发

- 客户端在进入发布页前、发布新闻前、进入修改页前、修改前、删除新闻前先向服务端发送请求携带token请求头
- 后端接收token请求头后,校验用户登录是否过期并做响应
- 前端根据响应信息提示用户进入登录页还是进入正常业务页面

 

controller

 //检查token是否过期
    @GetMapping("checkLogin")
    public Result checkLogin(@RequestHeader String token){
        Result result = userService.checkLogin(token);
        return result;
    }

service

   @Override
    public Result checkLogin(String token) {
        boolean tokem = jwtHelper.isExpiration(token);
        if(tokem){
            return Result.build(null,ResultEnum.TOken);
        }

        return Result.ok(null);
    }

编写拦截器

【所有/headline开头都需要检查登陆】

@Component
public class HeadlineInterceptors implements HandlerInterceptor {

    @Autowired
    private JwtHelper jwtHelper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

   //     System.out.println(jwtHelper);
        // 获取请求头中的token
       String token = request.getHeader("token");
//        System.out.println(jwtHelper);
  //      System.out.println(token);
        if (StringUtils.isEmpty(token) || jwtHelper.isExpiration(token)){
            Result result = Result.build(null, ResultEnum.TOken);
            ObjectMapper objectMapper = new ObjectMapper();
                //转化成json形式
            String json = objectMapper.writeValueAsString(result);
            response.getWriter().print(json);
            //拦截
            System.out.println("拦截了--------------------------");
            return false;
        }else{
            //放行
            System.out.println("放行了--------------------------");
            return true;
        }
        }


    }

 拦截器配置

@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

    @Autowired
    private HeadlineInterceptors HeadlineInterceptors;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(HeadlineInterceptors).addPathPatterns("/headline/*");//配置拦截器和拦截路径
    }
}

- 用户在客户端输入发布的新闻信息完毕后
- 发布前先请求后端的登录校验接口验证登录
- 登录通过则提交新闻信息
- 后端将新闻信息存入数据库

 

controller

 @PostMapping("publish")
    public Result publish(@RequestHeader String token, @RequestBody Headline headline){
        Result publish = headlineService.publish(token, headline);
        return  publish;
    }

service

    @Override
    public Result publish(String token, Headline headline) {

            int id = jwtHelper.getUserId(token).intValue();
            headline.setPublisher(id);
            headline.setPageViews(0);
            headline.setCreateTime(new Date());
            headline.setUpdateTime(new Date());
            headlineMapper.insert(headline);
            return Result.ok(null);

    }

- 前端先调用登录校验接口,校验登录是否过期
- 登录校验通过后 ,则根据新闻id查询新闻的完整信息并响应给前端

 

controller

   @PostMapping("findHeadlineByHid")
    public Result findHeadlineByHid(@RequestParam int hid){
        Result findHeadlineByHid = headlineService.findHeadlineByHid(hid);
        return findHeadlineByHid;
    }

service

    @Override
    public Result findHeadlineByHid(int hid) {
        Headline headline = headlineMapper.selectById(hid);
        HashMap<String, Object> map = new HashMap<>();
        map.put("headline", headline);
        return Result.ok(map);
    }

- 客户端将新闻信息修改后,提交前先请求登录校验接口校验登录状态
- 登录校验通过则提交修改后的新闻信息,后端接收并更新进入数据库

 

controller

    @PostMapping("update")
    public Result update(@RequestBody Headline headline){
                Result update = headlineService.update(headline);
        return update;
    }

service

   @Override
    public Result update(Headline headline) {
        headline.setUpdateTime(new Date());
        headlineMapper.updateById(headline);
        return Result.ok(null);
    }

- 将要删除的新闻id发送给服务端
- 服务端校验登录是否过期,未过期则直接删除,过期则响应登录过期信息

 

controller

  @Override
    public Result removeByHid(int hid) {
        headlineMapper.deleteById(hid);
        return Result.ok(null);
    }

项目实战二(小项目)

还是那几个依赖,这里不演示了

配置文件也是那几个,参考上面

数据库

CREATE TABLE schedule (
  id INT NOT NULL AUTO_INCREMENT,
  title VARCHAR(255) NOT NULL,
  completed BOOLEAN NOT NULL,
  PRIMARY KEY (id)
);

INSERT INTO schedule (title, completed)
VALUES
    ('学习java', true),
    ('学习Python', false),
    ('学习C++', true),
    ('学习JavaScript', false),
    ('学习HTML5', true),
    ('学习CSS3', false),
    ('学习Vue.js', true),
    ('学习React', false),
    ('学习Angular', true),
    ('学习Node.js', false),
    ('学习Express', true),
    ('学习Koa', false),
    ('学习MongoDB', true),
    ('学习MySQL', false),
    ('学习Redis', true),
    ('学习Git', false),
    ('学习Docker', true),
    ('学习Kubernetes', false),
    ('学习AWS', true),
    ('学习Azure', false);
/* 
需求说明
    查询全部数据页数据
请求uri
    schedule/{pageSize}/{currentPage}
请求方式 
    get   
响应的json
    {
        "code":200,
        "flag":true,
        "data":{
            //本页数据
            data:
            [
            {id:1,title:'学习java',completed:true},
            {id:2,title:'学习html',completed:true},
            {id:3,title:'学习css',completed:true},
            {id:4,title:'学习js',completed:true},
            {id:5,title:'学习vue',completed:true}
            ], 
            //分页参数
            pageSize:5, // 每页数据条数 页大小
            total:0 ,   // 总记录数
            currentPage:1 // 当前页码
        }
    }
*/

controller

    @GetMapping("/{pageSize}/{currentPage}")
    public Result getSchedule(@PathVariable("pageSize") int pageSize, @PathVariable("currentPage") int currentPage) {


        Result result = service.schedule(pageSize,currentPage);
        return result;
    }

service

    @Override
    public Result schedule(int pageSize, int currentPage) {
        Page<Schedule> page = new Page<>(currentPage, pageSize);
         scheduleMapper.selectPage(page, null);
        HashMap<String, Object> map = new HashMap<>();
        map.put("data",page.getRecords()); //获取数据
        map.put("pageSize",page.getSize()); //获取每页大小
        map.put("total",page.getTotal()); //获取总条数
        map.put("currentPage",page.getCurrent()); //获取页面
        return Result.ok(map);

    }
/* 
需求说明
    根据id删除日程
请求uri
    schedule/{id}
请求方式 
    delete
响应的json
    {
        "code":200,
        "flag":true,
        "data":null
    }
*/

controller

  @DeleteMapping("/{id}")
    public Result getScheduleById(@PathVariable("id") int id) {
        Result result = service.deleteSchedule(id);
        return result;
    }

service

   @Override
    public Result deleteSchedule(int id) {
        int i = scheduleMapper.deleteById(id);
        if (i == 1) {
            return Result.ok(null);
        } else
            return Result.fail(null);
    }
/* 
需求说明
    增加日程
请求uri
    schedule
请求方式 
    post
请求体中的JSON
    {
        title: '',
        completed: false
    }
响应的json
    {
        "code":200,
        "flag":true,
        "data":null
    }
*/

controller 

 @PostMapping
    public Result addSchedule(@RequestBody Schedule schedule) {
        Result result = service.addSchedule(schedule);
        return result;
    }

service

   @Override
    public Result addSchedule(Schedule schedule) {
        int i = scheduleMapper.insert(schedule);
        if (i == 1) {
            return Result.ok(null);
        } else
            return Result.fail(null);
    }
/* 
需求说明
    根据id修改数据
请求uri
    schedule
请求方式 
    put
请求体中的JSON
    {
        id: 1,
        title: '',
        completed: false
    }
响应的json
    {
        "code":200,
        "flag":true,
        "data":null
    }
*/

controller 

    @PutMapping
    public Result updateSchedule(@RequestBody Schedule schedule) {
                Result result = service.updateSchedule(schedule);
        return result;
    }

service

  @Override
    public Result updateSchedule(Schedule schedule) {
        int i = scheduleMapper.updateById(schedule);
        if (i == 1) {
            return Result.ok(null);
        } else
            return Result.fail(null);
    }

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您想要了解关于springboot项目实战的内容。我可以为您提供一些基本的信息,帮助您入门。 Spring Boot是一个基于Spring框架的快速开发Web应用的框架,它可以提供一些默认的配置,使得开发者可以更快的进行开发。下面是一些Spring Boot项目实战的经验: 1. 创建一个Spring Boot项目 您可以通过Spring Boot官网提供的Spring Initializr来创建一个Spring Boot项目,它提供了一个可视化的界面,您可以选择您所需的依赖和配置,然后下载生成的项目。 2. 配置数据库 Spring Boot框架提供了对多种数据库的支持,您可以通过配置文件来配置您需要使用的数据库。例如,如果您想使用MySQL数据库,可以在application.properties或application.yml文件中进行配置: ``` spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 3. 编写Controller 在Spring Boot中,您可以使用注解来标记您的Controller类和方法,使其能够接受HTTP请求并返回响应。例如: ``` @RestController @RequestMapping("/hello") public class HelloController { @GetMapping public String hello() { return "Hello, Spring Boot!"; } } ``` 4. 使用模板引擎 Spring Boot提供了对多种模板引擎的支持,例如Thymeleaf、Freemarker、Velocity等。您可以在pom.xml文件中添加对应的依赖,然后在Controller中使用模板引擎来渲染页面。 5. 部署应用程序 最后,您可以使用Spring Boot提供的打包工具将应用程序打包成可执行的jar文件,然后在服务器上运行它。您也可以将应用程序部署到云平台,例如AWS、Azure、Heroku等。 希望这些信息能帮助您入门Spring Boot项目实战。如有疑问,可以随时向我提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值