【SpringBoot】头条新闻项目实现CRUD登录注册

文章目录

  • 一、头条案例介绍
  • 二、技术栈介绍
  • 三、前端搭建
  • 四、基于SpringBoot搭建项目基础架构
    • 4.1 数据库脚本执行
    • 4.2 搭建SprintBoot工程
      • 4.2.1 导入依赖:
      • 4.2.2 编写配置
      • 4.2.3 工具类准备
    • 4.3 MybatisX逆向工程
  • 五、后台功能开发
  • 5.1 用户模块开发
    • 5.1.1 jwt 和 token 介绍
    • 5.1.2 jwt 使用与测试
    • 5.1.3 用户登录接口实现
    • 5.1.4 根据token获取用户数据
    • 5.1.5 注册用户名占用情况检查
    • 5.1.6 用户注册
  • 5.2 首页模块开发
    • 5.2.1 查询首页分类
    • 5.2.2 *分页查询首页头条信息
    • 5.2.3 *查询头条详情 (多表
  • 5.3 头条模块开发
    • 5.3.1 登陆验证和保护
    • 5.3.2 头条发布实现
    • 5.3.3 修改头条回显
    • 5.3.4 头条修改实现
    • 5.3.5 删除头条功能
  • 总结


一、头条案例介绍

Github项目 : springboot-headline-part,新闻管理CRUD系统登录注册

  • 用户功能
    • 注册功能
    • 登录功能
    • 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

三、前端搭建

npm install 
npm run dev

四、基于SpringBoot搭建项目基础架构

4.1 数据库脚本执行

CREATE DATABASE sm_db;

USE sm_db;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for news_headline
-- ----------------------------
DROP TABLE IF EXISTS `news_headline`;
CREATE TABLE `news_headline`  (
  `hid` INT NOT NULL AUTO_INCREMENT COMMENT '头条id',
  `title` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头条标题',
  `article` VARCHAR(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头条新闻内容',
  `type` INT NOT NULL COMMENT '头条类型id',
  `publisher` INT NOT NULL COMMENT '头条发布用户id',
  `page_views` INT NOT NULL COMMENT '头条浏览量',
  `create_time` DATETIME(0) NULL DEFAULT NULL COMMENT '头条发布时间',
  `update_time` DATETIME(0) NULL DEFAULT NULL COMMENT '头条最后的修改时间',
  `version` INT DEFAULT 1 COMMENT '乐观锁',
  `is_deleted` INT DEFAULT 0 COMMENT '头条是否被删除 1 删除  0 未删除',
  PRIMARY KEY (`hid`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;



-- ----------------------------
-- Table structure for news_type
-- ----------------------------
DROP TABLE IF EXISTS `news_type`;
CREATE TABLE `news_type`  (
  `tid` INT NOT NULL AUTO_INCREMENT COMMENT '新闻类型id',
  `tname` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '新闻类型描述',
  `version` INT DEFAULT 1 COMMENT '乐观锁',
  `is_deleted` INT DEFAULT 0 COMMENT '头条是否被删除 1 删除  0 未删除',
  PRIMARY KEY (`tid`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of news_type
-- ----------------------------
INSERT INTO `news_type` (tid,tname) VALUES (1, '新闻');
INSERT INTO `news_type` (tid,tname) VALUES (2, '体育');
INSERT INTO `news_type` (tid,tname) VALUES (3, '娱乐');
INSERT INTO `news_type` (tid,tname) VALUES (4, '科技');
INSERT INTO `news_type` (tid,tname) VALUES (5, '其他');

-- ----------------------------
-- Table structure for news_user
-- ----------------------------
DROP TABLE IF EXISTS `news_user`;
CREATE TABLE `news_user`  (
  `uid` INT NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `username` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户登录名',
  `user_pwd` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户登录密码密文',
  `nick_name` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户昵称',
  `version` INT DEFAULT 1 COMMENT '乐观锁',
  `is_deleted` INT DEFAULT 0 COMMENT '头条是否被删除 1 删除  0 未删除',
  PRIMARY KEY (`uid`) USING BTREE,
  UNIQUE INDEX `username_unique`(`username`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of news_user
-- ----------------------------
INSERT INTO `news_user` (uid,username,user_pwd,nick_name) VALUES (1, 'zhangsan', 'e10adc3949ba59abbe56e057f20f883e', '张三');
INSERT INTO `news_user` (uid,username,user_pwd,nick_name) VALUES (2, 'lisi', 'e10adc3949ba59abbe56e057f20f883e', '李四');
INSERT INTO `news_user` (uid,username,user_pwd,nick_name) VALUES (5, 'zhangxiaoming', 'e10adc3949ba59abbe56e057f20f883e', '张小明');
INSERT INTO `news_user` (uid,username,user_pwd,nick_name)VALUES (6, 'xiaohei', 'e10adc3949ba59abbe56e057f20f883e', '李小黑');

SET FOREIGN_KEY_CHECKS = 1;

4.2 搭建SprintBoot工程

  • 创建boot工程 : springboot-headline-part

4.2.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>com.wake</groupId>
    <artifactId>springboot-headline-part</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis-plus  -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

        <!-- 数据库相关配置启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- druid启动器的依赖  -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-3-starter</artifactId>
            <version>1.2.18</version>
        </dependency>

        <!-- 驱动类-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>


    <!--    SpringBoot应用打包插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

4.2.2 编写配置

# server配置
server:
  port: 8080
  servlet:
    context-path: /

# 连接池配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      url: jdbc:mysql:///sm_db
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

# mybatis-plus的配置
mybatis-plus:
  type-aliases-package: com.wake.pojo
  global-config:
    db-config:
      logic-delete-field: isDeleted  #全局逻辑删除
      id-type: auto #主键策略自增长
      table-prefix: news_ # 设置表的前缀
  • druid兼容springboot3文件
    • META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure
  • 启动类和mybatis-plus配置
@MapperScan("com.wake.mapper")
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }

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

4.2.3 工具类准备

1

结果封装类

package com.wake.utils;

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

解决枚举类

package com.wake.utils;

/**
 * 统一返回结果状态信息类
 */
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加密工具类

package com.wake.utils;

import org.springframework.stereotype.Component;

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);
        }
    }
}

4.3 MybatisX逆向工程

1
1
1
完善实体类注解,注意yml已经全局配置的
主键注解、乐观锁、逻辑删除、版本Version

  • pojo实体类 属性ID 添加 @TableId
  • version版本属性 添加 @Version

五、后台功能开发

5.1 用户模块开发

5.1.1 jwt 和 token 介绍

1. token
令牌(Token):一种代表某种访问权限身份认证信息的令牌。

可以是一串随机生成的字符或数字,用于验证用户的身份或授权用户对特定资源的访问。

1

  • 每个用户生成的唯一字符串标识,可以进行用户识别和校验
  • token验证标识无法直接识别用户的信息,盗取token后也无法`登录`程序! 相对安全!
  • Token是一项规范和标准(接口)

2.jwt
JWT(JSON Web Token)是具体可以生成,校验,解析等动作Token的技术(实现类)
在这里插入图片描述

jwt 工作流程:

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

jwt数据组成和包含信息:
JWT由三部分组成: header(头部).payload(载荷).signature(签名)
1 jwt可以携带很多信息! 一般情况,需要加入:有效时间,签名秘钥,其他用户标识信息!

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

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

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

5.1.2 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>
  • 配置yml
#jwt配置
jwt:
  token:
    tokenExpiration: 120 #有效时间,单位分钟
    tokenSignKey: headline123456  #当前程序签名秘钥 自定义      
  • 导入工具类
    封装jwt技术工具类
package com.wake.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;
        }
    }
}
  • 测试
@SpringBootTest
public class SbTest {

    @Autowired
    private JwtHelper jwtHelper;

    @Test
    public void test_jwt() {
        //生成 传入用户标识
        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);
    }
}

1

5.1.3 用户登录接口实现

  1. 需求描述
    1
    用户客户端输入用户名密码,向后端提交,后端根据用户名密码响应对应提示信息。

  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":{}
}
  1. 代码实现
    controller:
@CrossOrigin
@RestController
@RequestMapping("user")
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<UserMapper, User>
        implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtHelper jwtHelper;

    @Override
    public Result login(User user) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>();
        userLambdaQueryWrapper.eq(User::getUsername, user.getUsername());
        User loginUser = userMapper.selectOne(userLambdaQueryWrapper);

        if (loginUser == null) {
            return Result.build(null, ResultCodeEnum.USERNAME_ERROR);
        }

        //对比密码
        if (!StringUtils.isEmpty(loginUser.getUserPwd())
                && MD5Util.encrypt(user.getUserPwd()).equals(loginUser.getUserPwd())) {

            //根据用户ID生成token
            //并且将token封装进result返回
            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);
    }
}
  • 通过用户名查询 数据库中是否存在该User
    • 不存在,即返回501,输入的用户名有误
      • 需要直接判断整个User是否为空,因为查询返回的是一个User,而且是用 用户名查询数据库
      • 不要单独去判断用户名是否为空
    • 存在:即返回的User不为空,进入下一步 密码判断
  • 密码不为空且加密后密码对比 相等,允许登录且生成token
    1

5.1.4 根据token获取用户数据

  1. 需求描述
    客户端发送请求,提交token 请求头,后端根据token请求头获取登录用户的信息,并响应给用户。

此需求用于登陆之后,在前端页面可以获取使用用户信息,显示登陆信息的。像下列显示头像/用户名之类的…
1

  1. 接口描述
    url地址:user/getUserInfo
    请求方式:GET
    请求头:token: token内容

响应数据:

成功

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

失败

{
    "code": 504,
    "message": "notLogin",
    "data": null
}
  1. 代码实现
    注意:实体类Id属性 要添加@TableId注解 指定ID,不然查询ID会报错,查不到ID
  • controller
    @GetMapping("getUserInfo")
    public Result getUserInfo(@RequestHeader String token){
        Result result = userService.getUserInfo(token);
        return result;
    }
  • service
    @Override
    public Result getUserInfo(String token) {
        //判断token是否过期,TRUE到期,FALSE未到期
        if (jwtHelper.isExpiration(token)) {
            return Result.build(null,ResultCodeEnum.NOTLOGIN);
        }

        int userId = jwtHelper.getUserId(token).intValue();

        User user = userMapper.selectById(userId);
        user.setUserPwd("");

        Map map = new HashMap();
        map.put("loginUser",user);

        return Result.ok(map);
    }

先登录得到token,再查相应token。

  • 首先 判断token是否过期,过期登录失败
  • 在根据token获取uid(需要注解指定ID不然会有bug取不到id)
  • 根据ID获取user
  • 去掉密码内容
  • User封装map
    1

5.1.5 注册用户名占用情况检查

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

  2. 接口描述
    url地址:user/checkUserName
    请求方式:POST
    请求参数:param形式 : username=zhangsan

响应数据:

成功

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

失败

{
    "code":"505",
   "message":"用户名占用"
   "data":{}
}
  1. 代码实现

controller

    @PostMapping("checkUserName")
    public Result checkUserName(@RequestParam String username){
        Result result = userService.checkUserName(username);
        return result;
    }

service

userMapper.selectOne(userLambdaQueryWrapper);

    @Override
    public Result checkUserName(String username) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getUsername,username);

        User user = userMapper.selectOne(userLambdaQueryWrapper);

        //不为空,用户已存在
        if(user != null){
            return Result.build(null,ResultCodeEnum.USERNAME_USED);
        }

        return Result.ok(null);
    }

userMapper.selectCount(userLambdaQueryWrapper);

    @Override
    public Result checkUserName(String username) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getUsername,username);
        
        Long count = userMapper.selectCount(userLambdaQueryWrapper);
        
        //为0,没有数据
        if(count == 0){
            return Result.ok(null);
        }

        return Result.build(null,ResultCodeEnum.USERNAME_USED);
    }

1

5.1.6 用户注册

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

  2. 接口描述
    url地址:user/register
    请求方式:POST

请求参数:

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

{
    "username":"Doug",
    "userPwd":"123456", 
    "nickName":"道格"
}

响应数据:

成功

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

失败

{
   "code":"505",
   "message":"用户名占用"
   "data":{}
}
  1. 代码实现

注意:密码要MD5加密

controller

    @PostMapping("register")
    public Result register(@RequestBody User user){
        Result result = userService.register(user);
        return result;
    }

service

    /**
     * 注册
     * 1. 检查账号是否已被已被占用
     * 2. 密码加密MD5
     * 3. 账号数据保存insert
     * 4. 返回结果
     * @param user
     * @return
     */
    @Override
    public Result register(User user) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getUsername,user.getUsername());

        Long count = userMapper.selectCount(userLambdaQueryWrapper);
        
        if(count > 0){
            return Result.build(null,ResultCodeEnum.USERNAME_USED);
        }
        
        user.setUserPwd(MD5Util.encrypt(user.getUserPwd()));
        
        userMapper.insert(user);
        
        return Result.ok(null);
    }

1
1
1

5.2 首页模块开发

5.2.1 查询首页分类

  1. 需求描述
    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":"其他"
                }
            ]
    }
}
  1. 代码实现
    controller
@RestController
@CrossOrigin
@RequestMapping("portal")
public class PortalController {

    @Autowired
    private TypeService typeService;

    @GetMapping("findAllTypes")
    public Result findAllTypes(){
       Result result = typeService.findAllTypes();
       return result;
    }
}

service

@Service
public class TypeServiceImpl extends ServiceImpl<TypeMapper, Type>
    implements TypeService{

    @Autowired
    private TypeMapper typeMapper;

    @Override
    public Result findAllTypes() {
        List<Type> typeList = typeMapper.selectList(null);

        return Result.ok(typeList);
    }
}

1

5.2.2 *分页查询首页头条信息

  1. 需求:
    1
  • 客户端向服务端发送查询关键字,新闻类别,页码数,页大小
  • 服务端根据条件搜索分页信息,返回含页码数,页大小,总页数,总记录数,当前页数据等信息,并根据时间降序,浏览量降序排序
  1. 接口描述
    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 // 总记录数
    }
  }
}
  1. 代码实现
    请求参数 包装 Vo实体类
@Data
public class PortalVo {
    
    private String keyWords;
    private Integer type;
    private Integer pageNum = 1;
    private Integer pageSize =10;
}

controller

    @PostMapping("findNewsPage")
    public Result findNewsPage(@RequestBody PortalVo portalVo){
        Result result = headlineService.findNewsPage(portalVo);
        return result;
    }

service

@Service
public class HeadlineServiceImpl extends ServiceImpl<HeadlineMapper, Headline>
    implements HeadlineService{

    @Autowired
    private HeadlineMapper headlineMapper;

    /**
     * 首页数据查询
     *  1. 进行分页数据查询
     *  2. 分页数据,拼接到result即可
     *
     *  注意1 : 查询需要自定义语句,自定义Mapper的方法,携带分页
     *  注意2 : 返回结果List<Map>
     *
     *      第一层pageInfo 由service层 IPage<Headline>整理完包装成pageInfoMap 返回给controller层
     *          第二层的pageData 自定义查询语句,包装成List<Headline>
     *
     * @param portalVo
     * @return
     */
    @Override
    public Result findNewsPage(PortalVo portalVo) {
        //配置分页参数,当前页码数和当前页多少条
        IPage<Headline> page = new Page<>(portalVo.getPageNum(), portalVo.getPageSize());
        //自定义查询语句,portalVo传递keyword和type用于数据库查询
        headlineMapper.selectMyPage(page, portalVo);

        Map pageInfo = new HashMap();
        List<Headline> records = page.getRecords();
        pageInfo.put("pageData",records);
        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);
        return Result.ok(pageInfoMap);
    }
}

mapper

    /**
     * 定义分页查询方法,返回map格式数据
     * @param page
     * @param portalVo
     * @return
     */
    IPage<Headline> selectMyPage(IPage page, @Param("portalVo") PortalVo 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>

1

5.2.3 *查询头条详情 (多表

  1. 需求
    1
  • 用户点击"查看全文"时,向服务端发送新闻id
  • 后端根据新闻id查询完整新闻文章信息并返回
  • 后端要同时让新闻的浏览量+1
  1. 接口描述
    url地址:portal/showHeadlineDetail
    请求方式:post
    请求参数:
hid=1 param形成参数

响应数据:
成功

{
    "code":"200",
    "message":"success",
    "data":{
        "headline":{
            "hid":"1",                     // 新闻id 
            "title":"马斯克宣布 ... ...",   // 新闻标题
            "article":"... ..."            // 新闻正文
            "type":"1",                    // 新闻所属类别编号
            "typeName":"科技",             // 新闻所属类别
            "pageViews":"40",              // 新闻浏览量
            "pastHours":"3" ,              // 发布时间已过小时数
            "publisher":"1" ,              // 发布用户ID
            "author":"张三"                 // 新闻作者
        }
    }
}
  1. 代码实现
    controller
    @PostMapping("showHeadlineDetail")
    public Result showHeadlineDetail(@RequestParam String hid){
        Result result = headlineService.showHeadlineDetail(hid);
        return result;
    }

service

    /**
     * 根据id查询详情
     * 1. 查询对应的数据即可【多表查询,头条和用户表,自定义Mapper方法 返回map】
     * 2. 修改阅读量 【 "pageViews":"40",   // 新闻浏览量; 涉及到乐观锁需要当前数据对应版本】
     *
     * @param hid
     * @return
     */
    @Override
    public Result showHeadlineDetail(String hid) {
        Map data = headlineMapper.selectDetailByHidMap(hid);

        HashMap headlineMap = new HashMap();
        headlineMap.put("headline", data);

        // 修改阅读量+1,version乐观锁
        Headline headline = new Headline();
        headline.setHid((Integer) data.get("hid"));
        headline.setVersion((Integer) data.get("version"));
        headline.setPageViews((Integer) data.get("pageViews") + 1);

        headlineMapper.updateById(headline);

        return Result.ok(headlineMap);
    }

mapper

    /**
     * 多表查询,新闻详情
     * @param hid
     * @return
     */
    Map selectDetailByHidMap(String hid);

mapper.xml

    <select id="selectDetailByHidMap" resultType="map">
        select hid,title,article,type, h.version ,tname typeName ,page_views pageViews
             ,TIMESTAMPDIFF(HOUR,create_time,NOW()) pastHours,publisher
             ,nick_name author from news_headline h
                                        left join news_type t on h.type = t.tid
                                        left join news_user u  on h.publisher = u.uid
        where hid = #{hid}
    </select>

1

5.3 头条模块开发

5.3.1 登陆验证和保护

  1. 需求
    1
  • 客户端在进入发布页前、发布新闻前、进入修改页前、修改前、删除新闻前先向服务端发送请求携带token请求头
  • 后端接收token请求头后,校验用户登录是否过期并做响应
  • 前端根据响应信息提示用户进入登录页还是进入正常业务页面
  1. 接口描述
    url地址:user/checkLogin
    请求方式:get
    请求参数: 无
    请求头: token: 用户token

响应数据:

未过期:

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

过期:

{
    "code":"504",
    "message":"loginExpired",
    "data":{}
}
  1. 代码实现
    controller : 【登录检查】
    UserController
    @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);
    }

拦截器 【所有/headline 开头的都需要检查登录状态】
package com.wake.interceptors;

/**
 * @Description: 登录包含拦截器,检查请求头是否包含有效token
 * 有 有效 放行
 * 没有 无效 返回504
 */
@Component
public class LoginProtectedInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtHelper jwtHelper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 请求头从获取token
        String token = request.getHeader("token");
        // 检查是否有效
        if (StringUtils.isEmpty(token) || jwtHelper.isExpiration(token)) {
            // 无效返回504的状态json
            Result<Object> result = Result.build(null, ResultCodeEnum.NOTLOGIN);

            // 能将result对象转为字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(result);
            response.getWriter().print(json);

            return false;
        }
        // 有效放行
        return true;
    }
}

拦截器配置
在这里插入图片描述

/**
 * @Description: 添加拦截器
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginProtectedInterceptor loginProtectedInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginProtectedInterceptor).addPathPatterns("/headline/**");
    }
}

5.3.2 头条发布实现

  1. 需求
    1
  • 用户在客户端输入发布的新闻信息完毕后
  • 发布前先请求后端的登录校验接口验证登录
  • 登录通过则提交新闻信息
  • 后端将新闻信息存入数据库
  1. 接口描述
    url地址:headline/publish
    请求方式:post
    请求头 : token: … …

请求参数:

{
    "title":"文章标题 ... ...",   // 文章标题
    "article":"... 文章内容 ...",          // 文章内容
    "type":"1"                    // 文章类别
}

响应数据:

未登录

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

成功

{
    "code":"200",
    "message":"success",
    "data":{}
}
  1. 代码实现
    controller
@RestController
@CrossOrigin
@RequestMapping("headline")
public class HeadlineController {

    @Autowired
    private HeadlineService headlineService;


    /**
     * 登录后才能 发布新闻
     * @param headline
     * @param token
     * @return
     */
    @PostMapping("publish")
    public Result publish(@RequestBody Headline headline,@RequestHeader String token){
        Result result = headlineService.publish(headline,token);
        return result;
    }
}

service
headline

    @Override
    public Result publish(Headline headline, String token) {
        // token 查询用户id
        int userId = jwtHelper.getUserId(token).intValue();
        headline.setPublisher(userId);
        headline.setPageViews(0);
        headline.setCreateTime(new Date());
        headline.setUpdateTime(new Date());

        headlineMapper.insert(headline);

        return Result.ok(null);
    }

1

5.3.3 修改头条回显

  1. 需求
    1
  • 前端先调用登录校验接口,校验登录是否过期
  • 登录校验通过后 ,则根据新闻id查询新闻的完整信息并响应给前端
  1. 接口描述
    url地址:headline/findHeadlineByHid
    请求方式:post

请求参数:

hid=1 param形成参数

响应数据:
成功

{
    "code":"200",
    "message":"success",
    "data":{
        "headline":{
            "hid":"1",
            "title":"马斯克宣布",
            "article":"... ... ",
            "type":"2"
        }
    }
}
  1. 代码实现
    controller
    也可以直接调用service的继承的方法
    @PostMapping("findHeadlineByHid")
    public Result findHeadlineByHid(@RequestParam String hid) {
        Headline headline = headlineService.getById(hid);
        Map map = new HashMap();
        map.put("headline", headline);
        return Result.ok(map);
    }

先登录,拿到token
1

5.3.4 头条修改实现

  1. 需求
  • 客户端将新闻信息修改后,提交前先请求登录校验接口校验登录状态
  • 登录校验通过则提交修改后的新闻信息,后端接收并更新进入数据库
  1. 接口描述
    url地址:headline/update
    请求方式:post

请求参数:

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

响应数据:
成功

{
    "code":"200",
    "message":"success",
    "data":{}
}
  1. 代码实现

controller

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

service
直接更新前需要设置version乐观锁 以及 最新时间节点
然后再更新

    /**
     * 修改头条新闻
     * 1. hid查询数据的最新version
     * 2. 修改数据的更新时间为当前节点
     * @param headline
     * @return
     */
    @Override
    public Result updateData(Headline headline) {
        Integer version = headlineMapper.selectById(headline.getHid()).getVersion();

        //乐观锁
        headline.setVersion(version);
        headline.setUpdateTime(new Date());

        headlineMapper.updateById(headline);
        
        return Result.ok(null);
    }

1

5.3.5 删除头条功能

  1. 需求
    在这里插入图片描述- 将要删除的新闻id发送给服务端
  • 服务端校验登录是否过期,未过期则直接删除,过期则响应登录过期信息
  1. 接口描述
    url地址:headline/removeByHid
    请求方式:post

请求参数 : hid=1 param形成参数

响应数据:成功

{
    "code":"200",
    "message":"success",
    "data":{}
}
  1. 代码实现
    controller
    @PostMapping("removeByHid")
    public Result removeByHid(@RequestParam String hid){
        headlineService.removeById(hid);
        return Result.ok(null);
    }

1
1


总结

SSM官方笔记
1

头条新闻纯JavaWeb项目实现 1
JavaWeb_头条新闻项目实现 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/468923.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

8.发布页面

发布页面 官网 https://vkuviewdoc.fsq.pub/components/form.html 复制官网中的内容 代码 write.vue <template><view class"u-wrap u-p-l-20 u-p-r-20"><u-form :model"addModel" ref"form1"><u-form-item label&quo…

SegFormer 项目排坑记录

SegFormer 项目排坑记录 任务记录创建conda环境 准备数据库和预训练参数程序配置修改测试可视化训练 任务 需要复现SegFormer分割项目&#xff0c;似乎还有点麻烦&#xff0c;参考这几个进行复现&#xff0c;记录下过程&#xff1a; SegFormer mmsegmentation CSDN博客 知乎博…

CentOS的安装

一、打开VMware的WorkStation的软件界面。点击创建新的虚拟机。 二、我们选择自定义&#xff0c;下一步。 三、这个界面不用动&#xff0c;直接进入下一步。 四、点击稍后安装操作系统&#xff0c;下一步。 五、选择Linux操作系统&#xff0c;版本为CentOS 7 64位。 六、虚拟机…

备战蓝桥杯Day31 - 真题-管道

题目描述 解题思路 这个问题可以视为一个水波在管道中传播的问题&#xff0c;其中水波以单位速度传播。阀门在 S 时刻打开&#xff0c;水流以单位速度流向管道的右侧&#xff0c;每个传感器位于每段管道的中心。对于位于 Li 的阀门&#xff0c;在 Ti 时刻打开时&#xff0c;水…

Docker Desktop 安装 ClickHouse 超级简单教程

Docker desktop 安装 clickhouse 超级简单 文章目录 Docker desktop 安装 clickhouse 超级简单 什么是 Docker &#xff1f;安装下准备安装Docker配置安装 ClickHouse配置数据库密码DBeaver 测试创建表总结 什么是 Docker &#xff1f; 下载 Docker desktop Docker Desktop …

网络编程:多点通信+域套接字

一、多点通信 1.网络属性 getsockopt和setsockopt int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 功能&#xff1a;获取或设置套接字…

【Pt】ID贴图的基本使用

目标 将小白人样本的脸部区域填充为红色&#xff0c;如下 步骤 1. 首先这里打开一个软件自带的样本 2. 添加一个填充图层 3. 设置Base Color为红色 4. 添加黑色遮罩 5. 鼠标右键点击遮罩&#xff0c;然后添加颜色选择 6. 点击选取颜色就可以看到不同的ID部分 此时鼠标会变为滴…

个人信息的动态表单

有一系列需要勾选的内容&#xff0c;勾选完内容后&#xff0c;会根据勾选内容自动生成一个对应的表单。 不同的勾选内容&#xff0c;生成的表单内容是不一样的。 checkbox勾选方法&#xff1a; private void checkBox1_CheckedChanged(object sender, EventArgs e){this.te…

深入理解nginx连接数限制模块[下]

目录 4 源码分析4.1 配置指令源码分析4.1.1 limit_conn_zone4.1.2 limit_conn4.1.3 limit_conn_log_level4.1.4 limit_conn_status4.1.5 limit_conn_dry_run 4.2 共享内存初始化4.3 模块初始化4.4 请求处理4.5 红黑树的查找4.6 请求关闭的析构函数 关注我的微信公众号: 上接 …

DBSCAN聚类原理及Python实现

文章目录 一、相关术语二、DBSCAN原理2.1 算法思想及步骤2.2 优缺点分析2.3 Python代码 三、运行效率加速 一、相关术语 密度&#xff1a;指定半径内点的个数&#xff1b;核心点&#xff1a;如果某个点的半径邻域epsilon内至少包含minPts个点数&#xff0c;它就是核心点&#…

Spring Security的开发

文章目录 1,介绍2, 核心流程3, 核心原理3.1 过滤器链机制3.2 主体3.3 认证3.4 授权3.5 流程图4, 核心对象4.1 UserDetailsService 接口4.2 PasswordEncoder 接口4.3 hasAuthority方法4.4 hasAnyAuthority方法4.5 hasRole方法4.5 hasAnyRole方法5, 核心注解5.1 @PreAuthorize5.1…

十四、ReadWriteLock

ReadWriteLock 读写锁 又叫排他锁 如果使用互斥锁&#xff0c;一个线程在读&#xff0c;其他线程也不能读也不能写 换成读写锁的时候&#xff0c;读线程是读锁&#xff0c;写线程是写锁&#xff0c;写锁是排他的 在多线程大大提高效率&#xff0c;当一个线程在读的时候&…

MybatisPlus逆向工程

目录 &#x1f9c2;1.前提说明 &#x1f37f;2.引入依赖 &#x1f32d;3.使用导入模板 1.前提说明 注意 适用版本&#xff1a;mybatis-plus-generator 3.5.1 以下版本&#xff0c;3.5.1 及以上的请参考 3.5.1以上参考官网&#xff1a;3.5.1以上逆向工程 2.引入依赖 …

用 二层口 实现三层口 IP 通信的一个实现方法

我们一般用 undo portswitch 来将二层口转为三层口&#xff0c;但如果设备不支持的话&#xff0c;那么。。。 一、拓朴图&#xff1a; 二、实现方法&#xff1a; 起一个 vlan x&#xff0c;配置 vlanif地址&#xff0c;然后二层口划分到 vlan x 下&#xff0c;对端做同样的配置…

C语言 实用调试技巧

我们的博客已经更新到了数据结构&#xff0c;但是当我在深耕数据结构时我发现我在C语言是遗漏了一个重要的东西&#xff0c;那就是C语言的使用调试技巧。这篇博客对数据结构非常重要&#xff0c;请大家耐心观看。 1. 什么是bug&#xff1f; 第一次被发现的导致计算机错误的飞蛾…

Centos虚拟机忘记密码;重置虚机密码

虚拟机是一个好用的工具&#xff0c;在本地搭建的虚拟机可以给我们提供测试&#xff0c;但时间长了也会忘记密码&#xff1b;因此这里以centos系统的虚机为例&#xff0c;提供一个重置虚机密码的方法 1.在开机页面按“E”进入编辑模式 进入后长这样&#xff1a; 2.找到ro cras…

Python面向对象——架构设计【2】

练习1&#xff1a;打电话 请使用面向对象思想描述下列情景: 小明使用手机打电话,还有可能使用座机.... class People:def __init__(self,name):self.name namedef call_up(self,tool):print(self.name,end"")tool.call()class Tools:def __init__(self,way):self.wa…

【第十三章】改进神经网络学习方式-其他正则化技术

L1正则化 除了L2正则化之外&#xff0c;还有许多正则化技术。事实上&#xff0c;已经开发出了如此多的技术&#xff0c;以至于我不可能总结它们。在本节中&#xff0c;我简要介绍了三种减少过拟合的其他方法&#xff1a;L1正则化、dropout和人为增加训练集大小。我们不会像之前…

四.流程控制(顺序,分支,循环,嵌套)

c刚刚转过来的记得写在public static void main&#xff08;String[] args&#xff09;的花括号里 一.顺序结构 二.分支结构 if &#xff0c;switch 1.if (条件判断&#xff09; 2.if else 3.if else if else if ... else(它是一个一个否定来一个个执行判断的 4.s…

Gitee 实战配置

一、Gitee 注册帐号 官网&#xff1a;https://gitee.com点击注册按钮。填写姓名。填写手机号。填写密码。点击立即注册按钮 二、安装GIT获取公钥 1.官网下载git下载地址&#xff1a;https://git-scm.com/download/win 2.安装git&#xff0c;双击运行程序&#xff0c;然后一直下…