使用idea集成的springboot实现注册接口

跟黑马程序员学pringboot3+vue3,代码都是黑马程序员视频里的代码

实战篇-03_注册接口_哔哩哔哩_bilibili

本文仅仅用于学习记录

开发用户接口

注册接口

开发流程:明确需求>>阅读接口文档>>思路分析>>开发>>测试

分析:

这个图是截黑马ppt的图:

问题(今天在注册这个接口这里都搞不定!!!遇到很多问题!!!)

问题1:

因为有写依赖与springboot项目依赖版本号不兼容

快速的解决方法:

直接新建springboot项目,并且勾选这些需要用到的依赖,就是自动生成兼容的依赖,复制生成的pom.xml文件替换原来的pom.xml文件,修改一下pom的名字即可。

所以本菜鸟更喜欢一开始就建立springboot项目,哭了。。。。。。。

新建项目

创建实体类

首先先在启动类的包下创建以下几个包:(项目结构)

controller包

service包

(service包下再新建一个Impl包)

mapper包

pojo包

utils包

根据数据库表结构,在 pojo 包下创建 User.java 实体类

package com.example.demo.pojo;



import lombok.Data;

import java.time.LocalDateTime;

@Data
public class User {
    private Integer id;//主键ID
    private String username;//用户名
    private String password;//密码
    private String nickname;//昵称
    private String email;//邮箱
    private String userPic;//用户头像地址
    private LocalDateTime createTime;//创建时间
    private LocalDateTime updateTime;//更新时间
}

自动给实体类生成Geeter和Setter方法

  1. 在pom.xml中添加lombok依赖

2.在实体类中添加@Data

        

在application.yml文件配置配置数据库连接信息

废话来了:我们开发的是注册接口,需要往数据库里添加用户数据,所以一开始就把数据库连接信息配置好

路径:src/main/resources/application.properties

先把application.properties文件改造为application.yml 

(如何修改 ,这里有:配置文件application.properties-CSDN博客 中的yml部分)

配置数据库信息:

server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/big_event
    username: root
    password: 123456

查看接口文档,了解注册接口post请求长这样

http://localhost:8080/user/register?username=user1&password=123456

创建控制器

在 src/main/java/com/example/demo/controller 包下创建 UserController.java 控制器。

定义注册接口 /register 并实现注册逻辑

package com.example.demo.controller;


import com.example.demo.pojo.Result;
import com.example.demo.pojo.User;
import com.example.demo.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/*
@Resource注解用于自动注入依赖的 Bean。它是一个泛型注解,可以自动按类型注入,
也可以通过指定 name 属性来注入特定的 Bean。
*/

@Resource

/*@RestController注解用于将类标记为控制器,主要用来处理 HTTP 请求。
它相当于 @Controller 和 @ResponseBody 注解的组合,表示类中的方法返回的数据直接写入 HTTP 响应体中,而不是返回一个视图名称。
*/

@RestController

/*
@RequestMapping("/user")注解用于映射 HTTP 请求到控制器的处理方法。
这里指定了所有以 "/user" 开头的请求都会被这个控制器处理。
*/
@RequestMapping("/user")


public class UserController {

/*
@Autowired注解也是用于自动注入依赖的 Bean,
通常用于字段、构造函数、设置方法和普通方法参数。
它通过类型来自动注入 Bean,如果存在多个同类型的 Bean,
则需要通过 @Qualifier 注解指定具体的 Bean 名称
*/
    @Autowired
    private UserService userService;

/*
@PostMapping("/register")注解用于映射 HTTP POST 请求到特定的处理方法。
这里指定了当接收到 "/user/register" 的 POST 请求时,会调用 register 方法
*/
    @PostMapping("/register")
    public Result register(String username, String password){
        //查询用户名是否已存在
        User user =userService.findByUserName(username);
        if(user == null){
            userService.register(username,password);
            return Result.success();
        }else{
            //占用
            return Result.error("用户名已经被占用");
        }
    }



}

“不知道Bean注入的,看一下Bean部分的内容”

创建服务层接口和实现(实验查询用户是否存在和注册用户的业务逻辑)

在 src/main/java/com/example/demo/service 包下创建 UserService.java 接口

package com.example.demo.service;


import com.example.demo.pojo.User;

public interface UserService {
    // 根据用户名查询用户
     User findByUserName(String username) ;
//注册
     void register(String username, String password) ;
}

在 src/main/java/com/example/demo/service /Impl包下创建 UserServiceImpl.java 实现 UserService 接口

package com.example.demo.service.impl;


import com.example.demo.mapper.UserMapper;
import com.example.demo.pojo.User;
import com.example.demo.service.UserService;
import com.example.demo.utils.Md5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/*
@Service注解用于标记服务层的组件,它指示 Spring 容器将这个类作为一个 Bean 进行管理。
通常用于业务逻辑层,但不限于此
*/
@Service
public class UserServiceImpl implements UserService {

/*
@Autowired注解用于自动注入依赖的 Bean。
在这个例子中,它被用来自动注入 UserMapper 类的实例,
这是数据访问层的一个组件
*/
    @Autowired
    private UserMapper usermapper;
    @Override
    public User findByUserName(String username){
       User user = usermapper.findByUserName(username);
       return user;
    }
    @Override
    public void register(String username, String password){
        //加密
       String md5String= Md5Util.getMD5String(password);
       //添加
        usermapper.add(username,md5String);

    }
}

创建 MyBatis Mapper 接口(与数据库交互,进行数据库操作就写在这里)

在 src/main/java/com/example/demo/mapper 包下创建 UserMapper.java 接口

package com.example.demo.mapper;

import com.example.demo.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {
    //根据用户名查询添加
    @Select("select * from user where username = #{username}")
    User findByUserName(String username) ;
    //添加用户
    @Insert("insert into user(username,password,create_time,update_time) values(#{username},#{password},now(),now())")
    void add(String username, String password);
}
/*
@Mapper这是 MyBatis 提供的一个注解,用于标记 Mapper 接口。
当 Spring 扫描到这个注解时,它会为这个接口创建一个代理对象,
这个代理对象会实现接口中定义的所有方法,并处理 SQL 映射。

@Select这是 MyBatis 的注解,用于标记执行查询操作的方法。
在这个例子中,@Select 用于定义一个 SQL 查询语句,该语句根据提供的用户名查询用户。

@Insert这是 MyBatis 的注解,用于标记执行插入操作的方法。
在这个例子中,@Insert 用于定义一个 SQL 插入语句,该语句将新用户的信息插入到数据库中。
*/

/*
@Select("select * from user where username = #{username}")
User findByUserName(String username) ;
当 Spring 容器中的 MyBatis 代理对象调用 findByUserName 方法时,
MyBatis 框架会执行以下步骤:
将方法的 username 参数替换 SQL 语句中的 #{username} 占位符。
执行生成的 SQL 查询。
将查询结果(如果有的话)映射到 User 类的实例上。
返回 User 对象给调用者。
*/

创建 MD5 工具类

数据库密码一般都不使用明文,要进行加密

在 src/main/java/com/example/demo/utils 包下创建 Md5Util.java 工具类,用于密码加密。

package com.example.demo.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Md5Util {
    /**
     * 默认的密码字符串组合,用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
     */
    protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    protected static MessageDigest messagedigest = null;

    static {
        try {
            messagedigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException nsaex) {
            System.err.println(Md5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");
            nsaex.printStackTrace();
        }
    }

    /**
     * 生成字符串的md5校验值
     *
     * @param s
     * @return
     */
    public static String getMD5String(String s) {
        return getMD5String(s.getBytes());
    }

    /**
     * 判断字符串的md5校验码是否与一个已知的md5码相匹配
     *
     * @param password  要校验的字符串
     * @param md5PwdStr 已知的md5校验码
     * @return
     */
    public static boolean checkPassword(String password, String md5PwdStr) {
        String s = getMD5String(password);
        return s.equals(md5PwdStr);
    }


    public static String getMD5String(byte[] bytes) {
        messagedigest.update(bytes);
        return bufferToHex(messagedigest.digest());
    }

    private static String bufferToHex(byte bytes[]) {
        return bufferToHex(bytes, 0, bytes.length);
    }

    private static String bufferToHex(byte bytes[], int m, int n) {
        StringBuffer stringbuffer = new StringBuffer(2 * n);
        int k = m + n;
        for (int l = m; l < k; l++) {
            appendHexPair(bytes[l], stringbuffer);
        }
        return stringbuffer.toString();
    }

    private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
        char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>>
        // 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同
        char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
        stringbuffer.append(c0);
        stringbuffer.append(c1);
    }

}

创建统一响应结果类

查看接口文档:得到响应的数据类型

在 src/main/java/com/example/demo/pojo 包下创建 Result.java 类,用于封装 HTTP 响应

package com.example.demo.pojo;


import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {
    private Integer code;//业务状态码  0-成功  1-失败
    private String message;//提示信息
    private T data;//响应数据

    //快速返回操作成功响应结果(带响应数据)
    public static <E> Result<E> success(E data) {
        return new Result<>(0, "操作成功", data);
    }

    //快速返回操作成功响应结果
    public static Result success() {
        return new Result(0, "操作成功", null);
    }

    public static Result error(String message) {
        return new Result(1, message, null);
    }
}
/*
 @NoArgsConstructor是Lombok 库提供的注解,用于自动为类生成无参构造函数。
如果类中没有其他构造函数,使用这个注解可以避免手动编写无参构造函数。

@AllArgsConstructor是 Lombok 库提供的注解,用于自动为类生成包含所有字段作为参数的构造函数。
这在需要通过构造函数初始化所有属性时非常有用。

@Data是 Lombok 库提供的注解,用于自动为类生成 getters、setters、
equals()、hashCode() 和 toString() 方法。这可以显著减少样板代码。

*/
  • 当调用 success(E data) 方法时,会创建一个新的 Result 对象,其 code 设置为 0message 设置为 "操作成功"data 设置为传入的 data 参数。
  • 当调用 success() 方法时,会创建一个新的 Result 对象,其 code 和 message 与 success(E data) 方法相同,但 data 设置为 null
  • 当调用 error(String message) 方法时,会创建一个新的 Result 对象,其 code 设置为 1message 设置为传入的错误信息,data 设置为 null

Result<T> 是一个使用了泛型的Java类。让我们逐步解析一下:

Result: 这是一个类名,它被设计为一个容器或载体,用于封装从后端服务到前端或其他服务的数据传输结果。它通常包含了业务操作的状态、错误信息以及实际的数据。

<T>: 这是泛型的标记。T 是 Type 的缩写,它是一个占位符,代表任何类型的对象。当我们在定义 Result 类时,我们并不知道将来会存储哪种类型的数据,因此使用泛型 T 来表示可以存储任意类型的数据。

Result<T>: 当你看到 Result<T>,这意味着你可以创建一个 Result 类的对象,其中的 data 属性可以是任何类型的数据。例如,你可以有 Result<String>、Result<Integer> 或者 Result<List<User>> 等等。

实例化与使用:

如果你创建一个 Result<String> 对象,那么 T 就会被替换为 String 类型,意味着 data 属性将只能存储字符串。

如果你创建一个 Result<List<User>> 对象,T 将被替换为 List<User> 类型,意味着 data 属性将只能存储用户列表。

泛型的好处:

类型安全:编译器会在编译时检查类型,确保你不会把错误类型的对象放入 Result 中。

重用性:Result<T> 可以被用于多种类型的数据,提高了代码的灵活性和重用性。

所以,当你在代码中看到 Result<T>,它表示的是一个可以携带任意类型数据的结果对象。

在Java中,<E> Result<E> 是一个泛型方法的声明,它与泛型类的使用方式类似,但作用于方法级别。让我们详细解释一下这个声明:

<E>: 这个尖括号内的 E 定义了一个类型参数,它可以在方法内部作为类型占位符使用。E 通常代表“Element”或“Entity”,但它可以是任何合法的标识符。

Result<E>: 这是方法的返回类型,其中 <E> 表示返回的 Result 对象将具有一个名为 data 的字段,该字段的类型将由调用此方法时传入的实际类型决定。这里的 E 必须与前面的 <E> 相匹配,确保方法返回的 Result 对象的 data 字段类型与方法参数 data 的类型相同。

public static <E> Result<E> success(E data): 整体来看,这是一个静态泛型方法,它接收一个类型为 E 的参数 data,并返回一个类型为 Result<E> 的对象。这意味着无论你传递什么类型的参数给这个方法,返回的 Result 对象的 data 字段都将具有相同的类型。

例如,如果你这样调用该方法:

Result<String> result = Result.success("Hello, World!");

这里,E 被实例化为 String 类型,所以 result 将是一个 Result<String> 类型的对象,它的 data 字段将存储一个字符串 "Hello, World!"。

再比如

Result<Integer> result = Result.success(42);

这次,E 被实例化为 Integer 类型,所以 result 将是一个 Result<Integer> 类型的对象,它的 data 字段将存储整数 42。

通过使用泛型方法,你可以编写更加灵活且类型安全的代码,而无需为每种数据类型都编写一个专门的方法。

写在最后:搞了好久还遇到问题,难鼠了

出现HTTP 406 错误

原因:服务器无法满足请求者(客户端)所接受的响应内容类型。在这个情况下,客户端发送了一个 POST 请求到 /user/register 接口,期望接收 application/json 类型的数据,但是服务器没有正确处理这个请求,或者没有返回正确的 Content-Type

解决方法:在返回结果的实体类里添加@Data

最后的最后,成功了

使用 Lombok 的 @Data 注解可以自动生成必要的 getter 和 setter 方法,从而解决因缺少访问器方法而导致的 JSON 序列化问题。

为什么使用 @Data 注解可以解决问题?

  1. 对象序列化:在 Spring Boot 应用中,返回的对象通常需要被序列化为 JSON 格式。这通常是通过 Spring Boot 默认的 HttpMessageConverter 实现的,比如 MappingJackson2HttpMessageConverter

  2. Lombok 注解:Lombok 是一个 Java 库,它通过注解处理器在编译时自动生成常见的 Java 代码,如 getter、setter、构造函数、toString 方法等。@Data 注解是 Lombok 提供的一个强大注解,它等价于同时使用 @Getter@Setter@ToString@EqualsAndHashCode@RequiredArgsConstructor

  3. 自动生成访问器:当你在一个类上使用 @Data 注解时,Lombok 会自动为该类的所有字段生成 getter 和 setter 方法。这对于 JSON 序列化非常重要,因为 JSON 库(如 Jackson)需要通过这些访问器方法来访问对象的属性。

  4. 解决序列化问题:如果没有 getter 方法,JSON 序列化库可能无法访问对象的属性,从而导致序列化失败。这可能间接导致 Spring 返回 406 错误,因为客户端期望的是 JSON 响应,但服务器没有正确生成。

  5. 简化代码:使用 Lombok 可以大大减少样板代码,使开发者能够专注于业务逻辑。

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值