团队开发相关
说明:
建议一开始就是按着接口文档,从控制层找到对应接口开始一点点看下
不会的把对应的前后文都丢给gpt,让他给你解析
开发规范
RESTful
API规范
本处可以不用管,了解下就行,按照接口文档写的那样就行(apifox接口)
RESTful API规范(详细版)_restful api接口规范-优快云博客
后端三层结构
其他的你们都不用管,先点进去几个接口,看看具体的代码,其他包用到了再看
实体类命名规划(POJO)
Java学习笔记——实体类(ENTITY,VO,DTO,BO)_entity结尾的是-优快云博客
本处建议最好还是遵守下,特别是 前端给后端的数据 或者 后端给前端的数据 属性名称有区别时
- 不要再
entity
设置json
别名,这样就是一次性的,比如当后续前端又换一个名字时
例子:
前端需要的comment响应数据:
数据库对应的表单:
-- 创建 comment 表,用于存储商品评价信息 CREATE TABLE comments ( id BIGINT PRIMARY KEY AUTO_INCREMENT NOT NULL, -- 评价ID,自增主键 userId BIGINT NOT NULL, -- 评价用户的ID goodsId BIGINT NOT NULL, -- 商品ID goodsDetailId BIGINT NOT NULL, -- 商品规格详情ID orderId BIGINT NOT NULL, -- 订单ID content VARCHAR(500), -- 评价内容 score INT NOT NULL, -- 评分(如 1-5 分) createtime DATETIME NOT NULL -- 创建时间 );
本处评价内容等字段是不同的
对应的实体设计:
package com.wawu.pojo.entity; import lombok.Data; import java.time.LocalDateTime; @Data public class Comment { private Long id; private User user; private int score; // @JsonProperty("comment")//TODO 探究下这里是否有问题? //尽量别用这种这样可能会一次性 private String content;//comment // @JsonProperty("time") private LocalDateTime createTime; private String specName; private Long userId; private Long goodsId; private Long goodsDetailId; private Long orderId; }
vo设计:
本处需要返回的字段,也不需要那么多,最好不要直接用entity
package com.wawu.pojo.vo.GetGoodsCommentVO; import lombok.Data; import java.time.LocalDateTime; @Data public class CommentVO { private Long id; private UserVO user; private int score; private String comment; private LocalDateTime time; private String specName; } package com.wawu.pojo.vo.GetGoodsCommentVO; import lombok.Data; import java.util.List; @Data public class GoodCommentVO { private double rate;//均分=sum(评论评分)/总评论 private List<CommentVO> commentList; } package com.wawu.pojo.vo.GetGoodsCommentVO; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class UserVO { private String nickname; private String headimg;//头像 }
响应结果规范
返回一个Result
泛型对象
不懂代码的丢给gpt,让他给你例子
package com.wawu.common.result;
import lombok.Data;
import java.io.Serializable;
/**
* 后端统一返回结果
* @param <T>
*/
@Data
public class Result<T> implements Serializable {
private Integer code; //编码:0成功,1000和其它数字为失败
private String message; //错误信息
private T data; //数据
public static <T> Result<T> success() {
Result<T> result = new Result<T>();
result.code = 0;
return result;
}
public static <T> Result<T> success(T object) {
Result<T> result = new Result<T>();
result.data = object;
result.code = 0;
return result;
}
public static <T> Result<T> error(String msg) {
Result result = new Result();
result.message = msg;
result.code = 1000;
return result;
}
}
例子:
public static <T> Result<T> success(T object)
:
public static <T> Result<T> success()
:
package com.wawu.server.controller;
import com.wawu.common.annotation.IOC.Autowired;
import com.wawu.common.annotation.IOC.component.RestController;
import com.wawu.common.annotation.controller.mapping.PostMapping;
import com.wawu.common.annotation.controller.mapping.RequestMapping;
import com.wawu.common.annotation.controller.parameter.RequestBody;
import com.wawu.common.result.Result;
import com.wawu.pojo.dto.LoginDTO;
import com.wawu.pojo.entity.User;
import com.wawu.pojo.vo.LoginVO;
import com.wawu.server.service.UserService;
import java.sql.SQLException;
@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
UserService userService;
/**
* 用户登录
* @param loginDTO
* @return
*/
@PostMapping("/login")
// @OptionsMapping("/login")
public Result<LoginVO> login(@RequestBody LoginDTO loginDTO) throws SQLException {
LoginVO loginVO=userService.login(loginDTO);
return Result.success(loginVO);
}
/**
* 注册用户(这里就不用dto了,跟数据库表都是对应的)
* @param user
* @return
*/
@PostMapping("/signup")
public Result<LoginVO> signup(@RequestBody User user) throws SQLException {
LoginVO loginVO=userService.signup(user);
return Result.success(loginVO);
}
}
异常情况:
这里你们只需要抛出异常即可,其他的都不用管,自动调用public static <T> Result<T> error(String msg)
异常的信息建议都要直接写在代码中,最好封装到类中的静态变量中
例子:
package com.wawu.server.service;
import com.wawu.common.annotation.IOC.Autowired;
import com.wawu.common.annotation.IOC.component.Service;
import com.wawu.common.annotation.controller.parameter.RequestBody;
import com.wawu.common.constant.JwtClaimsConstant;
import com.wawu.common.constant.MessageConstant;
import com.wawu.common.exception.LoginException;
import com.wawu.common.property.JwtProperties;
import com.wawu.common.utils.JwtUtil;
import com.wawu.pojo.dto.LoginDTO;
import com.wawu.pojo.entity.User;
import com.wawu.pojo.vo.LoginVO;
import com.wawu.server.dao.UsersDAO;
import org.mindrot.jbcrypt.BCrypt;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
@Autowired
private UsersDAO usersDAO;
public LoginVO login(@RequestBody LoginDTO loginDTO) throws SQLException {
User user = usersDAO.getUser(User.builder().email(loginDTO.getAccount()).build());
//账号没有注册
if(user==null){
throw new LoginException(MessageConstant.LOGIN_EMAIL_NOT_REGISTER);
}
///。。。。其他代码省略
return loginVO;
}
}
备注:异常类也能直接用
BaseException
或者它的子类即可
package com.wawu.common.exception;
public class LoginException extends BaseException{
public LoginException() {
}
public LoginException(String msg) {
super(msg);
}
}
BaseException
子类
package com.wawu.common.constant;
public class MessageConstant {
public static final String LOGIN_EMAIL_NOT_REGISTER ="该邮箱还没注册,请前往注册";
public static final String LOGIN_PWD_NOT_ERROR="密码错误";
public static final String LOGIN_EMAIL_HAD_REGISTER="该邮箱已被注册";
public static final String LOGIN_NICKNAME_HAD_REGISTER="该昵称已被注册";
public static final String GOODS_DETAILS_STOCKNUM_LACK="当前规格的商品库存不足";
public static final String ORDER_NOT_EXIST ="订单不存在";
public static final String ORDER_COUNT_NOT_REPEAT_PURCHASE="订单不能重复购买";
}
本项目封装
只需会用,无需看懂所有代码
数据库开发小技巧
本处已经封装好了,具体代码请看对应的工具类
主要就是持久层的代码,这里不让用mybatis,只能自己封装了
设计思想:sql语句的生成与sql语句的执行分离
查询操作
对应工具类:
SelectSQLBuilder
主要方法:
其他大概看看,那部分还没有测试过,后续可能悔改
- 构造函数
- 动态条件中的普通条件
- 排序
- 获取sql和参数
这里就是借助chatgpt生成的
SelectSQLBuilder 使用文档
SelectSQLBuilder
是一个用于构建 SQL 查询语句的工具类,支持动态条件构建、排序、分组和分页等功能。
1. 初始化
SelectSQLBuilder builder = new SelectSQLBuilder("tableName");
传入表名
tableName
,初始化查询。
2. 动态条件
添加普通条件
builder.addDynamicCondition("fieldName", "operator", value);
fieldName
:字段名。operator
:运算符(=
,LIKE
,>
,<
等)。value
:条件值(null
值会被忽略)。示例:
builder.addDynamicCondition("email", "=", "test@example.com"); builder.addDynamicCondition("age", ">", 18);
添加 IN 条件
builder.addInCondition("fieldName", values);
fieldName
:字段名。values
:值的列表(List<?>
类型)。示例:
builder.addInCondition("status", List.of("active", "pending", "blocked"));
添加 BETWEEN 条件
builder.addBetweenCondition("fieldName", start, end);
fieldName
:字段名。start
:起始值。end
:结束值。示例:
builder.addBetweenCondition("created_at", "2023-01-01", "2023-12-31");
3. 查询字段
builder.selectFields("field1", "field2", "field3");
- 替换默认的
SELECT *
。示例:
builder.selectFields("id", "name", "email");
4. 分组
builder.addGroupBy("field1", "field2");
- 添加
GROUP BY
条件。示例:
builder.addGroupBy("category", "status");
5. 排序
builder.addOrderBy("fieldName", "ASC/DESC");
fieldName
:字段名。ASC/DESC
:排序方向。示例:
builder.addOrderBy("created_at", "DESC");
6. 分页
builder.addLimit(limit, offset);
limit
:每页的记录数。offset
:偏移量。示例:
builder.addLimit(10, 0);
7. 获取 SQL 和参数
String sql = builder.getSQL(); // 获取生成的 SQL 语句 Object[] params = builder.getParams(); // 获取对应的参数数组
示例:
String sql = builder.getSQL(); Object[] params = builder.getParams(); System.out.println("SQL: " + sql); System.out.println("Params: " + Arrays.toString(params));
完整示例
SelectSQLBuilder builder = new SelectSQLBuilder("users"); // 添加动态条件 builder.addDynamicCondition("email", "=", "test@example.com") .addInCondition("status", List.of("active", "pending")) .addBetweenCondition("created_at", "2023-01-01", "2023-12-31"); // 查询指定字段 builder.selectFields("id", "name", "email"); // 分组、排序和分页 builder.addGroupBy("status") .addOrderBy("created_at", "DESC") .addLimit(10, 0); // 获取 SQL 和参数 String sql = builder.getSQL(); Object[] params = builder.getParams(); System.out.println("Generated SQL: " + sql); System.out.println("Parameters: " + Arrays.toString(params));
输出示例:
Generated SQL: SELECT id, name, email FROM users WHERE email = ? AND status IN (?, ?) AND created_at BETWEEN ? AND ? GROUP BY status ORDER BY created_at DESC LIMIT 10 OFFSET 0 Parameters: [test@example.com, active, pending, 2023-01-01, 2023-12-31]
基于动态条件加强复用
例子:
package com.wawu.server.dao;
import com.wawu.common.annotation.IOC.component.Repository;
import com.wawu.common.utils.SQLBuilder.SelectSQLBuilder;
import com.wawu.common.utils.SQLExcutorUtil;
import com.wawu.pojo.entity.Good;
import java.sql.SQLException;
import java.util.List;
@Repository
public class GoodsDAO {
/**
* 动态条件查询商品列表
* @param goodQuery
* @return
* @throws SQLException
*/
public List<Good> getGoods(Good goodQuery) throws SQLException {
SelectSQLBuilder selectSqlBuilder =new SelectSQLBuilder("goods")
.addDynamicCondition("typeId","=", goodQuery.getTypeId())
.addDynamicCondition("id","=",goodQuery.getId())
.addOrderBy("createtime","DESC");
return SQLExcutorUtil.queryList(selectSqlBuilder.getSQL(),Good.class, selectSqlBuilder.getParams());
}
/**
* 根据类型动态获取商品基础信息(动态sql)(后续可以作废了,用类封装版)
* @param typeId
* @return
* @throws SQLException
*/
public List<Good> getGoodsByType(Long typeId) throws SQLException {
SelectSQLBuilder selectSqlBuilder =new SelectSQLBuilder("goods")
.addDynamicCondition("typeId","=", typeId)
.addOrderBy("createtime","DESC");
// System.out.println(sqlBuilder.getSQL());
return SQLExcutorUtil.queryList(selectSqlBuilder.getSQL(),Good.class, selectSqlBuilder.getParams());
}
//获取商品资料
public List<Good> getGoodsById(Long id) throws SQLException {
SelectSQLBuilder sqlBuilder=new SelectSQLBuilder("goods")
.addDynamicCondition("id","=", id)
.addOrderBy("createtime","DESC");
return SQLExcutorUtil.queryList(sqlBuilder.getSQL(),Good.class,sqlBuilder.getParams());
}
//搜索商品
public List<Good> searchGoods(String keyword) throws SQLException {
SelectSQLBuilder sqlBuilder=new SelectSQLBuilder("goods")
.addDynamicCondition("name","LIKE", keyword)
.addOrderBy("createtime","DESC");
return SQLExcutorUtil.queryList(sqlBuilder.getSQL(),Good.class,sqlBuilder.getParams());
}
}
此处像很多方法都能够整合到getGoods
,不要写那么多方法,到时候把goodQuery
不要的字段设置为空值或者不设置值就行
更新操作
对应的工具类:
public class UpdateSQLBuilder extends BaseSQLBuilder
跟上面是同理的动态更新
UpdateSQLBuilder 使用文档
UpdateSQLBuilder
是一个用于构建动态 SQL 更新语句的工具类,支持添加动态更新字段、批量字段更新以及条件约束。
1. 初始化
UpdateSQLBuilder builder = new UpdateSQLBuilder("tableName");
- 传入表名
tableName
,初始化更新构造器。
2. 添加更新字段
单个字段
builder.setField("fieldName", value);
fieldName
:字段名。value
:更新值(null
值会被忽略)。示例:
builder.setField("name", "John Doe"); builder.setField("age", 25);
多个字段
builder.setFields(Map<String, Object> fields);
fields
:Map<String, Object>
类型,键为字段名,值为更新值。示例:
builder.setFields(Map.of( "name", "John Doe", "age", 25, "email", "john.doe@example.com" ));
3. 添加动态条件
动态条件用于构建
WHERE
子句,支持动态添加。builder.addDynamicCondition("fieldName", "operator", value);
fieldName
:字段名。operator
:操作符(=
,LIKE
,>
,<
等)。value
:条件值(null
值会被忽略)。示例:
builder.addDynamicCondition("id", "=", 1); builder.addDynamicCondition("status", "=", "active");
4. 获取 SQL 和参数
获取 SQL
String sql = builder.getSQL();
- 获取完整的更新语句。
获取参数
Object[] params = builder.getParams();
- 获取与 SQL 对应的参数数组。
完整示例
UpdateSQLBuilder builder = new UpdateSQLBuilder("users"); // 设置更新字段 builder.setField("name", "Jane Doe") .setField("email", "jane.doe@example.com") .setFields(Map.of( "age", 30, "status", "active" )); // 添加条件 builder.addDynamicCondition("id", "=", 123) .addDynamicCondition("is_deleted", "=", false); // 获取 SQL 和参数 String sql = builder.getSQL(); Object[] params = builder.getParams(); System.out.println("Generated SQL: " + sql); System.out.println("Parameters: " + Arrays.toString(params));
输出示例
Generated SQL: UPDATE users SET name = ?, email = ?, age = ?, status = ? WHERE id = ? AND is_deleted = ? Parameters: [Jane Doe, jane.doe@example.com, 30, active, 123, false]
例子:
package com.wawu.server.dao;
import com.wawu.common.annotation.IOC.component.Repository;
import com.wawu.common.exception.BaseException;
import com.wawu.common.utils.SQLBuilder.SelectSQLBuilder;
import com.wawu.common.utils.SQLBuilder.UpdateSQLBuilder;
import com.wawu.common.utils.SQLExcutorUtil;
import com.wawu.pojo.entity.GoodDetail;
import java.sql.SQLException;
import java.util.List;
@Repository
public class GoodsDetailsDAO {
/**
* 根据id更新商品详情(目前只设置个库存)
* @param goodDetail
*/
public void update(GoodDetail goodDetail){
//先限制整一个异常,后续在搞吧,没啥时间了
if(goodDetail.getId()==null){
throw new BaseException("商品详情id为空,无法继续");
}
UpdateSQLBuilder updateSQLBuilder=new UpdateSQLBuilder("goodsdetails")
.setField("stockNum",goodDetail.getStockNum())
.addDynamicCondition("id","=",goodDetail.getId());//TODO: 待优化:这里不应该整成动态条件的
//这里异常其实可以先不加的
try {
// 调用 SQLExcutorUtil 的 update 方法执行更新
int rowsAffected = SQLExcutorUtil.update(updateSQLBuilder.getSQL(), updateSQLBuilder.getParams());
if (rowsAffected == 0) {
throw new BaseException("更新失败,未找到对应的记录");
}
} catch (SQLException e) {
throw new BaseException("数据库更新操作失败"+e);
}
}
}
- 此处也是动态更新,当为空值时不更新
sql语句执行
对应类
SQLExcutorUtil
:负责数据库的执行操作,以及封装了数据库的连接池只看主要方法,其他方法没有测试,特别是事务的,那个还没想好
主要方法:
- 单个对象查询
- 多个对象查询
- 查询标量值(就是像基础类型那样的)
- 更新操作(这里名字后续改:不仅仅是更新)
- 插入并获取生成的主键
SQLExcutorUtil 使用文档
SQLExcutorUtil
是一个简化数据库操作的工具类,支持通用的查询、更新、插入、批量更新和事务操作。调用者只需提供 SQL 语句和参数,无需关心底层数据库连接与资源管理。
1. 单个对象查询
<T> T SQLExcutorUtil.querySingle(String sql, Class<T> resultType, Object... params)
- 参数:
sql
:SQL 查询语句。resultType
:结果对象的类型。params
:SQL 参数。- 返回值: 查询的单个结果,类型为
T
。- 示例:
User user = SQLExcutorUtil.querySingle("SELECT * FROM users WHERE id = ?", User.class, 1);
2. 多个对象查询
<T> List<T> SQLExcutorUtil.queryList(String sql, Class<T> resultType, Object... params)
- 参数:
sql
:SQL 查询语句。resultType
:结果对象的类型。params
:SQL 参数。- 返回值: 查询结果的
List<T>
。- 示例:
List<User> users = SQLExcutorUtil.queryList("SELECT * FROM users WHERE age > ?", User.class, 18);
3. 查询标量值
<T> T SQLExcutorUtil.queryScalar(String sql, Class<T> resultType, Object... params)
- 参数:
sql
:SQL 查询语句。resultType
:结果值的类型。params
:SQL 参数。- 返回值: 单个标量值,类型为
T
。- 示例:
long userCount = SQLExcutorUtil.queryScalar("SELECT COUNT(*) FROM users", Long.class);
4. 更新操作
int SQLExcutorUtil.update(String sql, Object... params)
- 参数:
sql
:更新语句(INSERT
、UPDATE
或DELETE
)。params
:SQL 参数。- 返回值: 影响的行数。
- 示例:
int rowsUpdated = SQLExcutorUtil.update("UPDATE users SET name = ? WHERE id = ?", "John Doe", 1);
5. 插入并获取生成的主键
long SQLExcutorUtil.updateAndGetGeneratedKey(String sql, Object... params)
- 参数:
sql
:插入语句。params
:SQL 参数。- 返回值: 生成的主键(
long
类型)。- 示例:
long generatedId = SQLExcutorUtil.updateAndGetGeneratedKey("INSERT INTO users (name, age) VALUES (?, ?)", "Alice", 22);
6. 批量更新
int[] SQLExcutorUtil.batchUpdate(String sql, Object[][] params)
- 参数:
sql
:更新语句。params
:二维数组,每行代表一组参数。- 返回值: 每个批量操作影响的行数。
- 示例:
int[] results = SQLExcutorUtil.batchUpdate( "INSERT INTO users (name, age) VALUES (?, ?)", new Object[][] { {"Alice", 22}, {"Bob", 30} } );
7. 事务操作
void SQLExcutorUtil.transaction(Runnable... operations)
- 参数:
operations
:需要执行的多个操作,使用Runnable
实现。- 行为:
- 开启事务,依次执行所有操作,成功后提交事务。
- 如果任一操作抛出异常,则回滚事务。
- 示例:
SQLExcutorUtil.transaction( () -> SQLExcutorUtil.update("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100, 1), () -> SQLExcutorUtil.update("UPDATE accounts SET balance = balance + ? WHERE id = ?", 100, 2) );
完整示例
// 查询单个用户 User user = SQLExcutorUtil.querySingle("SELECT * FROM users WHERE id = ?", User.class, 1); // 查询多个用户 List<User> users = SQLExcutorUtil.queryList("SELECT * FROM users WHERE age > ?", User.class, 18); // 获取用户总数 long userCount = SQLExcutorUtil.queryScalar("SELECT COUNT(*) FROM users", Long.class); // 更新用户信息 int rowsUpdated = SQLExcutorUtil.update("UPDATE users SET name = ? WHERE id = ?", "John Doe", 1); // 插入用户并获取主键 long generatedId = SQLExcutorUtil.updateAndGetGeneratedKey( "INSERT INTO users (name, age) VALUES (?, ?)", "Alice", 22 ); // 批量插入用户 int[] batchResults = SQLExcutorUtil.batchUpdate( "INSERT INTO users (name, age) VALUES (?, ?)", new Object[][] { {"Alice", 22}, {"Bob", 30} } ); // 使用事务更新账户余额 SQLExcutorUtil.transaction( () -> SQLExcutorUtil.update("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100, 1), () -> SQLExcutorUtil.update("UPDATE accounts SET balance = balance + ? WHERE id = ?", 100, 2) );
JWT令牌
你只要知道就是解析
token
获取部分字段的工具就行对应代码
JWTUtil
:主要跟登录校验相关
用法例子:
挑着
token
看
package com.wawu.server.service;
import com.wawu.common.annotation.IOC.Autowired;
import com.wawu.common.annotation.IOC.component.Service;
import com.wawu.common.annotation.controller.parameter.RequestBody;
import com.wawu.common.constant.JwtClaimsConstant;
import com.wawu.common.constant.MessageConstant;
import com.wawu.common.exception.LoginException;
import com.wawu.common.property.JwtProperties;
import com.wawu.common.utils.JwtUtil;
import com.wawu.pojo.dto.LoginDTO;
import com.wawu.pojo.entity.User;
import com.wawu.pojo.vo.LoginVO;
import com.wawu.server.dao.UsersDAO;
import org.mindrot.jbcrypt.BCrypt;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserService {
@Autowired
private UsersDAO usersDAO;
//涉及到各种密码加密的一些东西
int saltRounds = 5; // 定义盐的复杂度
String salt = BCrypt.gensalt(saltRounds);
public LoginVO login(@RequestBody LoginDTO loginDTO) throws SQLException {
User user = usersDAO.getUser(User.builder().email(loginDTO.getAccount()).build());
//账号没有注册
if(user==null){
throw new LoginException(MessageConstant.LOGIN_EMAIL_NOT_REGISTER);
}
System.out.println(loginDTO);
System.out.println(user);
LoginVO loginVO=new LoginVO();
//校验密码
if(BCrypt.checkpw(loginDTO.getPwd(),user.getPwd())){
loginVO.setName(user.getNickname());
//JWT令牌存储内容:用户id
Map<String,Object> claims=new HashMap<>();//存放对应的的角色信息
claims.put(JwtClaimsConstant.USER_ID,user.getId());
loginVO.setToken(JwtUtil.createJWT(JwtProperties.secretKey,JwtProperties.ttl,claims));
System.out.println(JwtUtil.parseJWT(JwtProperties.secretKey,loginVO.getToken()));
}else{
throw new LoginException(MessageConstant.LOGIN_PWD_NOT_ERROR);
}
return loginVO;
}
/**
* 注册用户
* @param newUser
* @return
*/
public LoginVO signup(User newUser) throws SQLException {
//1. 判断是否已经被注册
User user = usersDAO.getUser(User.builder()
.email(newUser.getEmail()).build());
if(user!=null){
throw new LoginException(MessageConstant.LOGIN_EMAIL_HAD_REGISTER);
}
user = usersDAO.getUser(User.builder()
.nickname(newUser.getNickname()).build());
if(user!=null){
throw new LoginException(MessageConstant.LOGIN_NICKNAME_HAD_REGISTER);
}
//2. 插入数据
newUser.setCreatetime(LocalDateTime.now());
newUser.setUpdatetime(LocalDateTime.now());
newUser.setPwd(BCrypt.hashpw(newUser.getPwd(),salt));
newUser.setId(usersDAO.insert(newUser));
//3. 前端需要的返回数据
LoginVO loginVO=new LoginVO();
loginVO.setName(newUser.getNickname());
//JWT令牌存储内容:用户id
Map<String,Object> claims=new HashMap<>();//存放对应的的角色信息
claims.put(JwtClaimsConstant.USER_ID,newUser.getId());
loginVO.setToken(JwtUtil.createJWT(JwtProperties.secretKey,JwtProperties.ttl,claims));
System.out.println(JwtUtil.parseJWT(JwtProperties.secretKey,loginVO.getToken()));
return loginVO;
}
}
易错
JSON
格式
这里一定要对应对了,不然前端会报错
重点区分对象和数组
例子:
与这个响应为例
{
"code": 0,
"data": {
"rate": 32,
"commentList": [
{
"id": "7",
"user": {
"nickname": "wawu",
"headimg": "http://tvax4.sinaimg.cn/crop.0.0.480.480.180/768c39d5ly8fjje1d0teej20dc0dcq35.jpg"
},
"score": 60,
"comment": "起毛呀",
"time": "11-29 05:54",
"specName": "Size M"
},
{
"id": "2",
"user": {
"nickname": "User Two",
"headimg": "http://example.com/user2.jpg"
},
"score": 4,
"comment": "The t-shirt is very comfortable.",
"time": "10-22 09:32",
"specName": "Size M"
}
]
}
}
结构:
result{
code;
data{//对应的VO类
}
}
对应VO
对象封装:
package com.wawu.pojo.vo.GetGoodsCommentVO;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class CommentVO {
private Long id;
private UserVO user;
private int score;
private String comment;
private LocalDateTime time;
private String specName;
}
package com.wawu.pojo.vo.GetGoodsCommentVO;
import lombok.Data;
import java.util.List;
@Data
public class GoodCommentVO {
private double rate;//均分=sum(评论评分)/总评论
private List<CommentVO> commentList;
}
package com.wawu.pojo.vo.GetGoodsCommentVO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserVO {
private String nickname;
private String headimg;//头像
}
协作开发
代码仓库协作
冲突处理
此处一定一定一定要特别谨慎,出现冲突,最好别自己处理,直接来找我
教程:IDEA解决gitee,git冲突(stash changes和unstash changes的使用,两个人同时写在一行)_git unstash changes-优快云博客
接口文档
使用
apifox
,具体看那里,这里只是简单提一下
运行:
千万别动示例,如果是用示例运行,千万别保存
具体仓库参考示例
文档:
一定要看看