尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

码农世界 2024-06-17 后端 89 次浏览 0个评论

目录

项目模块

技术栈

功能展示

环境搭建

前端环境搭建:

后端环境搭建:

数据库创建:

(建议使用数据库软件操作)

springboot项目搭建:

mybatis-plus逆向工程

后端功能开发

用户模块开发

jwt 与 token

登录功能实现

根据token获取用户信息

注册用户名检查

用户注册功能

首页模块开发

查询首页分类

分页查询首页头条信息

查询头条详情

头条模块开发

登录验证和保护

头条发布实现

修改头条回显

头条修改实现

删除头条功能


完整后端代码:https://pan.baidu.com/s/1sEsK4x6uM_o32qdsVTxagQ?pwd=d67f

apifox测试文件:https://pan.baidu.com/s/11liz1MxjYeitrsJbua3VFA?pwd=k8we

项目模块

  • 用户功能
    • 注册功能
    • 登录功能
    • jwt实现
  • 头条新闻
    • 新闻的分页浏览
    • 通过标题关键字搜索新闻
    • 查看新闻详情
    • 新闻的修改和删除

    技术栈

    前端技术栈:

    • ES6作为基础JS语法
    • nodejs用于运行环境
    • npm用于项目依赖管理工具
    • vite用于项目的构建架工具
    • Vue3用于项目数据的渲染框架
    • Axios用于前后端数据的交互
    • Router用于页面的跳转
    • Pinia用于存储用户的数据
    • LocalStorage作为用户校验token的存储手段
    • Element-Plus提供组件

      后端技术栈:

      • JAVA作为开发语言,版本为JDK17
      • Tomcat作为服务容器,版本为10.1.7
      • Mysql8用于项目存储数据
      • SpringMVC用于控制层实现前后端数据交互
      • MyBatis-Plus用于实现数据的CURD
      • Druid用于提供数据源的连接池
      • SpringBoot作为项目基础架构
      • MD5用于用户密码的加密
      • Jwt用于token的生成和校验
      • Jackson用于转换JSON

        功能展示

        头条首页信息搜索尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        登录功能尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        注册功能尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        展示功能尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        发布头条功能

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        修改头条功能

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        环境搭建

        前端环境搭建:

        前端环境下载icon-default.png?t=N7T8https://pan.baidu.com/s/16HJROtpdTZ6DrL0GMNJncw?pwd=42wf

        下载后解压,使用vscode打开文件夹,在vscode中打开终端依次输入:

        npm install

        npm run dev

        后项目启动:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        后端环境搭建:

        数据库创建:
        (建议使用数据库软件操作)

        https://pan.baidu.com/s/19vKtJCn_CwyFHPwinpcmsA?pwd=fkky

        springboot项目搭建:

        1.创建boot工程:springboot-news

        2.导入依赖

        
        
            4.0.0
            
                org.springframework.boot
                spring-boot-starter-parent
                3.0.5
            
            com.qiu
            springboot-news
            1.0-SNAPSHOT
            
                
                    org.springframework.boot
                    spring-boot-starter-web
                
                
                
                    com.baomidou
                    mybatis-plus-boot-starter
                    3.5.3.1
                
                
                
                    org.springframework.boot
                    spring-boot-starter-jdbc
                
                
                
                    com.alibaba
                    druid-spring-boot-3-starter
                    1.2.18
                
                
                
                    mysql
                    mysql-connector-java
                    8.0.28
                
                
                    org.projectlombok
                    lombok
                    1.18.28
                
                
                    org.springframework.boot
                    spring-boot-starter-aop
                
                
                    org.springframework.boot
                    spring-boot-starter-test
                    test
                
            
            
                
                    
                        org.springframework.boot
                        spring-boot-maven-plugin
                    
                
            
        

        3.编写配置

        # server配置
        server:
          port: 8080
          servlet:
            context-path: /
        # 连接池配置
        spring:
          datasource:
            type: com.alibaba.druid.pool.DruidDataSource
            druid:
              url: jdbc:mysql:///sm_db
              username: root
              password: 123456
              driver-class-name: com.mysql.cj.jdbc.Driver
        # mybatis-plus的配置
        mybatis-plus:
          type-aliases-package: com.qiu.pojo
          global-config:
            db-config:
              logic-delete-field: isDeleted  #全局逻辑删除
              id-type: auto #主键策略自增长
              table-prefix: news_ # 设置表的前缀

        4.解决druid问题

        druid版本在1.2.20以下的需要:创建文件,添加内容

        文件名:org.springframework.boot.autoconfigure.AutoConfiguration.imports

        内容:com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        5.编写启动类和mybatis-plus插件

        包:com.qiu

        @SpringBootApplication
        @MapperScan("com.qiu.mapper")
        public class Main {
            public static void main(String[] args) {
                System.out.println("Hello world!");
                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;
            }
        }

        6.编写工具类

        包:com.qiu.utils

        结果封装类

        /**
         * 全局统一返回结果类
         */
        public class Result {
            // 返回码
            private Integer code;
            // 返回消息
            private String message;
            // 返回数据
            private T data;
            public Result(){}
            // 返回数据
            protected static  Result build(T data) {
                Result result = new Result();
                if (data != null)
                    result.setData(data);
                return result;
            }
            public static  Result build(T body, Integer code, String message) {
                Result result = build(body);
                result.setCode(code);
                result.setMessage(message);
                return result;
            }
            public static  Result build(T body, ResultCodeEnum resultCodeEnum) {
                Result result = build(body);
                result.setCode(resultCodeEnum.getCode());
                result.setMessage(resultCodeEnum.getMessage());
                return result;
            }
            /**
             * 操作成功
             * @param data  baseCategory1List
             * @param 
             * @return
             */
            public static Result ok(T data){
                Result result = build(data);
                return build(data, ResultCodeEnum.SUCCESS);
            }
            public Result message(String msg){
                this.setMessage(msg);
                return this;
            }
            public Result code(Integer code){
                this.setCode(code);
                return this;
            }
            public Integer getCode() {
                return code;
            }
            public void setCode(Integer 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;
            }
        }

        结果状态信息枚举类

        /**
         * 统一返回结果状态信息类
         *
         */
        public enum ResultCodeEnum {
            SUCCESS(200,"success"),
            USERNAME_ERROR(501,"usernameError"),
            PASSWORD_ERROR(503,"passwordError"),
            NOTLOGIN(504,"notLogin"),
            USERNAME_USED(505,"userNameUsed");
            private Integer code;
            private String message;
            private ResultCodeEnum(Integer code, String message) {
                this.code = code;
                this.message = message;
            }
            public Integer getCode() {
                return code;
            }
            public String getMessage() {
                return message;
            }
        }
        

        MD5加密工具类

        import java.security.MessageDigest;
        import java.security.NoSuchAlgorithmException;
        @Component
        public final 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();
                    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加密出错!!+" + e);
                }
            }
        }
        mybatis-plus逆向工程

        1.逆向工程

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        2.完善pojo类

        删除@TableName注解,全局统一设置

        添加主键,乐观锁,逻辑删除注解

        @Data
        public class User implements Serializable {
            @TableId
            private Integer uid;
            private String username;
            private String userPwd;
            private String nickName;
            @Version
            private Integer version;
            @TableLogic
            private Integer isDeleted;
            private static final long serialVersionUID = 1L;
        }

        后端功能开发

        用户模块开发

        jwt 与 token

        令牌(token):用于验证用户身份或授权用户对特定资源的访问。普通令牌可以以多种形式出现:访问令牌,身份令牌,刷新令牌等。

        就是在用户登录后生成一段字符或数字给他,用户之后每次访问都携带这个token来证明自己的身份,这段字符或数字就是token

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        JWT介绍

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

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

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        JWT工作流程

        1. 用户通过其凭据(通常为账号密码)进行身份认证
        2. 服务器对凭据进行验证,验证成功后创建一个JWT
        3. 服务器将JWT发送给客户端,客户端在之后的请求中将JWT添加到请求头或参数中
        4. 服务器接收请求后,验证JWT的签名和有效性,并根据JWT中的声明进行身份验证和授权操作

        JWT的数据组成和包含信息

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

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        jwt可以携带很多信息:有效时间,签名秘钥,其他用户标识信息等

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

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

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

        JWT的使用

        1.导入依赖

        
            io.jsonwebtoken
            jjwt
            0.9.1
        
        
            javax.xml.bind
            jaxb-api
            2.3.0
        

        2.编写配置

        application.yaml

        jwt:
          token:
        #    tokenExpiration: 120 #有效时间,单位分钟
            tokenExpiration: 1 #为了测试token过期,设置一分钟
            tokenSignKey: qiu666 #当前程序签名秘钥 自定义

        3.导入工具类

        @Component
        @Data
        @ConfigurationProperties(prefix = "jwt.token")
        public class JwtHelper {
            //有效时间,单位毫秒 1000毫秒 == 1秒
            private long tokenExpiration;
            //当前程序签名秘钥
            private String tokenSignKey;
            //生成token
            public String createToken(Long userId){
                String token = Jwts.builder().setSubject("YYGH-USER")
        //                1分钟
                        .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration * 1000 * 60))
                        //存放数据
                        .claim("userId", userId)
                        //签名,当用户请求时携带token,根据签名判断身份是否通过
                        .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                        .compressWith(CompressionCodecs.GZIP).compact();
                return token;
            }
            //当用户请求中携带token时,从token中获取数据(useId)
            public Long getUserId(String token){
                //StringUtils的包为com.baomidou.mybatisplus.core.toolkit.StringUtils;
                if (StringUtils.isEmpty(token))return null;
                Jws 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;
                }
            }
        }

        4.使用和测试

        @SpringBootTest
        public class JwtTest {
            @Autowired
            private JwtHelper jwtHelper;
            @Test
            public void test() throws InterruptedException {
                //生成数据 用户数据 userId 1L
                String token = jwtHelper.createToken(1L);
                System.out.println("token = " + token);
                //解析用户标识
                Long userId = jwtHelper.getUserId(token);
                System.out.println("userId = " + userId);
                //查看token是否过期 false 未到期 true到期
                boolean expiration = jwtHelper.isExpiration(token);;
                System.out.println("expiration = " + expiration);
                Thread.sleep(1000*60);
                System.out.println(" 程序睡眠一分钟后: ");
                //查看token是否过期 false 未到期 true到期
                boolean expiration1 = jwtHelper.isExpiration(token);;
                System.out.println("expiration = " + expiration1);
            }
        }
        

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        登录功能实现

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

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        2.接口描述:

        url:user/login

        请求方式:POST

        请求参数:

        {
            "username":"zhangsan",
            "userPwd":"123456"
        }

        响应数据:

        成功

        {
           "code":"200",         // 成功状态码 
           "message":"success"   // 成功状态描述
           "data":{
            "token":"... ..." // 用户id的token
          }
        }

        失败

        {
           "code":"501",
           "message":"用户名有误"
           "data":{}
        }
        或者
        {
           "code":"503",
           "message":"密码有误"
           "data":{}
        }

        3.实现代码:

        controller:

        @RestController
        @RequestMapping("user")
        @CrossOrigin    //解决跨域问题
        public class UserController {
            @Autowired
            private UserService userService;
            @PostMapping("login")
            public Result login(@RequestBody User user){
                Result result = userService.login(user);
                return result;
            }
        }

        service:

        @Service
        public class UserServiceImpl extends ServiceImpl
            implements UserService{
            @Autowired
            private JwtHelper jwtHelper;
            @Autowired
            private  UserMapper userMapper;
            /**
             * 登录业务实现
             * @param user
             * @return result封装
             */
            @Override
            public Result login(User user) {
                //根据账号查询
                LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(User::getUsername,user.getUsername());
                User loginUser = userMapper.selectOne(queryWrapper);
                //账号判断
                if (loginUser == null) {
                    //账号错误
                    return Result.build(null, ResultCodeEnum.USERNAME_ERROR);
                }
                //判断密码
                if (!StringUtils.isEmpty(user.getUserPwd())
                        && loginUser.getUserPwd().equals(MD5Util.encrypt(user.getUserPwd())))
                {
                   //账号密码正确
                    //根据用户唯一标识生成token
                    String token = jwtHelper.createToken(Long.valueOf(loginUser.getUid()));
                    Map data = new HashMap();
                    data.put("token",token);
                    return Result.ok(data);
                }
                //密码错误
                return Result.build(null,ResultCodeEnum.PASSWORD_ERROR);
            }
        }

        测试结果

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        根据token获取用户信息

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

        2.接口描述:

        url:user/getUserInfo

        请求方式:GET

        请求头:

        token:token内容

        响应数据:

        成功:

        {
            "code": 200,
            "message": "success",
            "data": {
                "loginUser": {
                    "uid": 1,
                    "username": "zhangsan",
                    "userPwd": "",
                    "nickName": "张三"
                }
            }
        }

        失败:

        {
            "code": 504,
            "message": "notLogin",
            "data": null
        }

        代码实现:

        controller:

        /**
         * 地址: user/getUserInfo
         * 方式: get
         * 请求头: token = token内容
         * 返回:
         *    {
         *     "code": 200,
         *     "message": "success",
         *     "data": {
         *         "loginUser": {
         *             "uid": 1,
         *             "username": "zhangsan",
         *             "userPwd": "",
         *             "nickName": "张三"
         *         }
         *      }
         *   }
         *
         * 大概流程:
         *    1.获取token,解析token对应的userId
         *    2.根据userId,查询用户数据
         *    3.将用户数据的密码置空,并且把用户数据封装到结果中key = loginUser
         *    4.失败返回504 (本次先写到当前业务,后期提取到拦截器和全局异常处理器)
         */
        @GetMapping("getUserInfo")
        public Result userInfo(@RequestHeader String token){
            Result result = userService.getUserInfo(token);
            return result;
        }

        service:

        /**
         * 查询用户数据
         * @param token
         * @return result封装
         */
        @Override
        public Result getUserInfo(String token) {
            //1.判定是否有效期
            if (jwtHelper.isExpiration(token)) {
                //true过期,直接返回未登录
                return Result.build(null,ResultCodeEnum.NOTLOGIN);
            }
            //2.获取token对应的用户
            int userId = jwtHelper.getUserId(token).intValue();
            //3.查询数据
            User user = userMapper.selectById(userId);
            if (user != null) {
                user.setUserPwd(null);
                Map data = new HashMap();
                data.put("loginUser",user);
                return Result.ok(data);
            }
            return Result.build(null,ResultCodeEnum.NOTLOGIN);
        }

        测试结果:尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        注册用户名检查

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

        2.接口描述:

        url:user/checkUserName

        请求方式:POST

        请求参数:param形式

        username=zhangsan

        响应数据:

        成功:

        {
           "code":"200",
           "message":"success"
           "data":{}
        }

        失败:

        {
            "code":"505",
           "message":"用户名占用"
           "data":{}
        }

        3.代码实现:

        controller:

        /**
         * url地址:user/checkUserName
         * 请求方式:POST
         * 请求参数:param形式
         * username=zhangsan
         * 响应数据:
         * {
         *    "code":"200",
         *    "message":"success"
         *    "data":{}
         * }
         *
         * 实现步骤:
         *   1. 获取账号数据
         *   2. 根据账号进行数据库查询
         *   3. 结果封装
         */
        @PostMapping("checkUserName")
        public Result checkUserName(String username){
            Result result = userService.checkUserName(username);
            return result;
        }

        service:

        /**
         * 检查账号是否可以注册
         *
         * @param username 账号信息
         * @return
         */
        @Override
        public Result checkUserName(String username) {
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername,username);
            User user = userMapper.selectOne(queryWrapper);
            if (user != null){
                return Result.build(null,ResultCodeEnum.USERNAME_USED);
            }
            return Result.ok(null);
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        用户注册功能

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

        2.接口描述:

        url:user/regist

        请求方式:POST

        请求参数:

        {
            "username":"zhangsan",
            "userPwd":"123456", 
            "nickName":"张三"
        }

        响应数据:

        成功:

        {
           "code":"200",
           "message":"success"
           "data":{}
        }

        失败:

         

        {
           "code":"505",
           "message":"用户名占用"
           "data":{}
        }

        3.代码实现:

        controller:

        /**
        * url地址:user/regist
        * 请求方式:POST
        * 请求参数:
        * {
        *     "username":"zhangsan",
        *     "userPwd":"123456",
        *     "nickName":"张三"
        * }
        * 响应数据:
        * {
        *    "code":"200",
        *    "message":"success"
        *    "data":{}
        * }
        *
        * 实现步骤:
        *   1. 将密码加密
        *   2. 将数据插入
        *   3. 判断结果,成 返回200 失败 505
        */
        @PostMapping("regist")
        public Result regist(@RequestBody User user){
          Result result = userService.regist(user);
          return result;
        }

        service:

        @Override
        public Result regist(User user) {
            LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getUsername,user.getUsername());
            Long count = userMapper.selectCount(queryWrapper);
            if (count > 0){
                return Result.build(null,ResultCodeEnum.USERNAME_USED);
            }
            user.setUserPwd(MD5Util.encrypt(user.getUserPwd()));
            int rows = userMapper.insert(user);
            System.out.println("rows = " + rows);
            return Result.ok(null);
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        首页模块开发

        查询首页分类

        1.需求:

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

        2.接口描述:

        url:portal/findAllTypes

        请求方式:GET

        请求参数:无

        响应数据:

        成功:

        {
           "code":"200",
           "message":"OK"
           "data":{
                    [
                        {
                            "tid":"1",
                            "tname":"新闻"
                        },
                        {
                            "tid":"2",
                            "tname":"体育"
                        },
                        {
                            "tid":"3",
                            "tname":"娱乐"
                        },
                        {
                            "tid":"4",
                            "tname":"科技"
                        },
                        {
                            "tid":"5",
                            "tname":"其他"
                        }
                    ]
            }
        }

        3.代码实现

        controller:

        @RestController
        @RequestMapping("portal")
        @CrossOrigin
        public class PortalController {
            @Autowired
            private TypeService typeService;
            /**
             * 查询全部类别信息
             * @return
             */
            @GetMapping("findAllTypes")
            public Result findAllTypes(){
                //直接调用业务层,查询全部数据
                List list = typeService.list();
                return  Result.ok(list);
            }
        }

        测试结果:尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        分页查询首页头条信息

        1.需求:

                客户端向服务端发送查询关键字,新闻类别,页码数,页大小

                服务端根据条件搜索分页信息,返回含页码数,页大小,总页数,总记录数,当前页数据等信息,并根据时间降序,浏览量降序排序

        2.接口描述:

        url:portal/findNewsPage

        请求方式:POST

        请求参数:

        {
            "keyWords":"马斯克", // 搜索标题关键字
            "type":0,           // 新闻类型
            "pageNum":1,        // 页码数
            "pageSize":10     // 页大小
        }

        响应数据:

        成功:

        {
           "code":"200",
           "message":"success"
           "data":{
              "pageInfo":{
                "pageData":[
                  {
                    "hid":"1",                     // 新闻id 
                    "title":"尚硅谷宣布 ... ...",   // 新闻标题
                    "type":"1",                    // 新闻所属类别编号
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3" ,              // 发布时间已过小时数
                    "publisher":"1"                // 发布用户ID
                },
                {
                    "hid":"1",                     // 新闻id 
                    "title":"尚硅谷宣布 ... ...",   // 新闻标题
                    "type":"1",                    // 新闻所属类别编号
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3",              // 发布时间已过小时数
                    "publisher":"1"                // 发布用户ID
                },
                {
                    "hid":"1",                     // 新闻id 
                    "title":"尚硅谷宣布 ... ...",   // 新闻标题
                    "type":"1",                    // 新闻所属类别编号
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3",               // 发布时间已过小时数
                    "publisher":"1"                // 发布用户ID
                }
                ],
              "pageNum":1,    //页码数
              "pageSize":10,  // 页大小
              "totalPage":20, // 总页数
              "totalSize":200 // 总记录数
            }
          }
        }

        3.代码实现:

        准备接收条件类:

        @Data
        public class PortalVo {
            
            private String keyWords;
            private Integer type;
            private Integer pageNum = 1;
            private Integer pageSize =10;
        }

        controller:

        /**
         * 首页分页查询
         * @return
         */
        @PostMapping("findNewPages")
        public Result findNewPage(@RequestBody PortalVo portalVo){
            Result result = headlineService.findNewPage(portalVo);
            return result;
        }

        service:

        @Service
        public class HeadlineServiceImpl extends ServiceImpl
            implements HeadlineService{
            @Autowired
            private HeadlineMapper headlineMapper;
            /**
             * 首页数据查询
             * @param portalVo
             * @return
             */
            @Override
            public Result findNewPage(PortalVo portalVo) {
                //1.条件拼接 需要非空判断
                LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.like(!StringUtils.isEmpty(portalVo.getKeyWords()),Headline::getTitle,portalVo.getKeyWords())
                        .eq(portalVo.getType()!= null,Headline::getType,portalVo.getType());
                //2.分页参数
                IPage page = new Page<>(portalVo.getPageNum(),portalVo.getPageSize());
                //3.分页查询
                //查询的结果 "pastHours":"3"   // 发布时间已过小时数 我们查询返回一个map
                //自定义方法
                headlineMapper.selectPageMap(page, portalVo);
                //4.结果封装
                //分页数据封装
                Map 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 pageInfoMap=new HashMap<>();
                pageInfoMap.put("pageInfo",pageInfo);
                // 响应JSON
                return Result.ok(pageInfoMap);
            }
        }

        mapper:

        接口:

        public interface HeadlineMapper extends BaseMapper {
            //自定义分页查询方法
            IPage selectPageMap(IPage page, 
                        @Param("portalVo") PortalVo portalVo);
        }

        mapper.xml:

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        查询头条详情

        1.需求:

                用户点击"查看全文"时,向服务端发送新闻id

                后端根据新闻id查询完整新闻文章信息并返回

                后端要同时让新闻的浏览量+1

        2.接口描述:

        url:portal/showHeadlineDetial

        请求方式:POST

        请求参数: param形式

        hid=1

        响应数据:

        成功:

        {
            "code":"200",
            "message":"success",
            "data":{
                "headline":{
                    "hid":"1",                     // 新闻id 
                    "title":"马斯克宣布 ... ...",   // 新闻标题
                    "article":"... ..."            // 新闻正文
                    "type":"1",                    // 新闻所属类别编号
                    "typeName":"科技",             // 新闻所属类别
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3" ,              // 发布时间已过小时数
                    "publisher":"1" ,              // 发布用户ID
                    "author":"张三"                 // 新闻作者
                }
            }
        }

        3.代码实现:

        controller:

         /**
         * 首页详情接口
         * @param hid
         * @return
         */
        @PostMapping("showHeadlineDetail")
        public Result showHeadlineDetail(Integer hid){
            Result result = headlineService.showHeadlineDetail(hid);
            return result;
        }

        service:

        /**
         * 详情数据查询
         * "headline":{
         * "hid":"1",                     // 新闻id
         * "title":"马斯克宣布 ... ...",   // 新闻标题
         * "article":"... ..."            // 新闻正文
         * "type":"1",                    // 新闻所属类别编号
         * "typeName":"科技",             // 新闻所属类别
         * "pageViews":"40",              // 新闻浏览量
         * "pastHours":"3" ,              // 发布时间已过小时数
         * "publisher":"1" ,              // 发布用户ID
         * "author":"张三"                 // 新闻作者
         * }
         * 注意: 是多表查询 , 需要更新浏览量+1
         *
         * @param hid
         * @return
         */
        @Override
        public Result showHeadlineDetail(Integer hid) {
            //1.实现根据id的查询(多表
            Map headLineDetail = headlineMapper.selectDetailMap(hid);
            //2.拼接头条对象(阅读量和version)进行数据更新
            Headline headline = new Headline();
            headline.setHid(hid);
            headline.setPageViews((Integer) headLineDetail.get("pageViews")+1); //阅读量+1
            headline.setVersion((Integer) headLineDetail.get("version")); //设置版本
            headlineMapper.updateById(headline);
            Map pageInfoMap=new HashMap<>();
            pageInfoMap.put("headline",headLineDetail);
            return Result.ok(pageInfoMap);
        }

        mapper:

        接口:

        /**
         * 分页查询头条详情
         * @param hid
         * @return
         */
        Map selectDetailMap(Integer hid);

        mapper.xml:

        
        

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        头条模块开发

        登录验证和保护

        1.需求:

                客户端在进入发布页前、发布新闻前、进入修改页前、修改前、删除新闻前先向服务端发送请求携带token请求头

                后端接收token请求头后,校验用户登录是否过期并做响应

                前端根据响应信息提示用户进入登录页还是进入正常业务页面

        2.接口描述:

        url:user/checkLogin

        请求方式:GET

        请求参数:无

        请求头:token: 用户token

        3.代码实现:

        controller:(登录后检查)

        @GetMapping("checkLogin")
        public Result checkLogin(@RequestHeader String token){
            if (StringUtils.isEmpty(token) || jwtHelper.isExpiration(token)){
                //没有传或者过期 未登录
                return Result.build(null, ResultCodeEnum.NOTLOGIN);
            }
            
            return Result.ok(null);
        }

        创建拦截器:

        @Component
        public class LoginProtectInterceptor implements HandlerInterceptor {
            @Autowired
            private JwtHelper jwtHelper;
            
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                String token = request.getHeader("token");
                if (StringUtils.isEmpty(token) || jwtHelper.isExpiration(token)){
                    Result result = Result.build(null, ResultCodeEnum.NOTLOGIN);
                    ObjectMapper objectMapper = new ObjectMapper();
                    String json = objectMapper.writeValueAsString(result);
                    response.getWriter().print(json);
                    //拦截
                    return false;
                }else{
                    //放行
                    return true;
                }
            }
        }

        配置拦截器:(使用 /headline 开头都拦截)

        @Configuration
        public class WebMvcConfig implements WebMvcConfigurer {
            @Autowired
            private LoginProtectInterceptor loginProtectInterceptor;
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(loginProtectInterceptor).addPathPatterns("/headline/**");
            }
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        头条发布实现

        1.需求:

                用户在客户端输入发布的新闻信息完毕后

                发布前先请求后端的登录校验接口验证登录

                登录通过则提交新闻信息

                后端将新闻信息存入数据库

        2.接口描述:

        url:headline/publish

        请求方式:POST

        请求头:token:用户token

        请求参数:

        {
            "title":"尚硅谷宣布 ... ...",   // 文章标题
            "article":"... ...",          // 文章内容
            "type":"1"                    // 文章类别
        }

        响应数据:

        未登录:

        {
            "code":"504",
            "message":"loginExpired",
            "data":{}
        }

        成功:

        {
            "code":"200",
            "message":"success",
            "data":{}
        }
        

        3.代码实现:

        controller:

        /**
         * 实现步骤:
         *   1. token获取userId [无需校验,拦截器会校验]
         *   2. 封装headline数据
         *   3. 插入数据即可
         */
        @PostMapping("publish")
        public Result publish(@RequestBody Headline headline,@RequestHeader String token){
            int userId = jwtHelper.getUserId(token).intValue();
            headline.setPublisher(userId);
            Result result = headlineService.publish(headline);
            return result;
        }

        service:

        /**
         * 发布数据
         * @param headline
         * @return
         */
        @Override
        public Result publish(Headline headline) {
            headline.setCreateTime(new Date());
            headline.setUpdateTime(new Date());
            headline.setPageViews(0);
            headlineMapper.insert(headline);
            return Result.ok(null);
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        修改头条回显

        1.需求:

                前端先调用登录校验接口,校验登录是否过期

                登录校验通过后 ,则根据新闻id查询新闻的完整信息并响应给前端

        2.接口描述:

        url:headline/findHeadlineByHid

        请求方式:POST

        请求参数:param形式

        hid=1

        响应数据:

        成功:

        {
            "code":"200",
            "message":"success",
            "data":{
                "headline":{
                    "hid":"1",
                    "title":"马斯克宣布",
                    "article":"... ... ",
                    "type":"2"
                }
            }
        }

        3.代码实现:

        controller:

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

        service:

        /**
         * 根据id查询详情
         * @param hid
         * @return
         */
        @Override
        public Result findHeadlineByHid(Integer hid) {
            Headline headline = headlineMapper.selectById(hid);
            Map pageInfoMap=new HashMap<>();
            pageInfoMap.put("headline",headline);
            return Result.ok(pageInfoMap);
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        头条修改实现

        1.需求:

                客户端将新闻信息修改后,提交前先请求登录校验接口校验登录状态

                登录校验通过则提交修改后的新闻信息,后端接收并更新进入数据库

        2.接口描述:

        url:headline/update

        请求方式:POST

        请求参数:

        {
            "hid":"1",
            "title":"尚硅谷宣布 ... ...",
            "article":"... ...",
            "type":"2"
        }

        响应数据:

        成功:

        {
            "code":"200",
            "message":"success",
            "data":{}
        }

        3.代码实现:

        controller:

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

        service:

         /**
         * 修改业务
         * 1.查询version版本
         * 2.补全属性,修改时间 , 版本!
         *
         * @param headline
         * @return
         */
        @Override
        public Result updateHeadLine(Headline headline) {
            //读取版本
            Integer version = headlineMapper.selectById(headline.getHid()).getVersion();
            headline.setVersion(version);
            headline.setUpdateTime(new Date());
            headlineMapper.updateById(headline);
            return Result.ok(null);
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码)

        删除头条功能

        1.需求:

                将要删除的新闻id发送给服务端

                服务端校验登录是否过期,未过期则直接删除,过期则响应登录过期信息

        2.接口描述:

        url:headline/removeByHid

        请求方式:POST

        请求参数:param形式

        hid=1

        响应数据:

        成功:

        {
            "code":"200",
            "message":"success",
            "data":{}
        }

        3.代码实现:

        controller:

        @PostMapping("removeByHid")
        public Result removeById(Integer hid){
            headlineService.removeById(hid);
            return Result.ok(null);
        }

        测试结果:

        尚硅谷SpringBoot项目--微头条实战(有完整项目代码) 

转载请注明来自码农世界,本文标题:《尚硅谷SpringBoot项目--微头条实战(有完整项目代码)》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,89人围观)参与讨论

还没有评论,来说两句吧...

Top