Compare commits

...

6 Commits

Author SHA1 Message Date
jsh
1a71904608 add: 登录 2025-10-12 16:13:35 +08:00
jsh
68474c0c80 add: 登录 2025-10-12 16:13:04 +08:00
jsh
23ff4c814d style: 修改注释 2025-10-12 14:49:01 +08:00
jsh
363bcb83c6 fix: 修复还有多少天变成负数的问题 2025-10-12 14:27:19 +08:00
jsh
0200382ddf style: 清理引入 2025-10-12 14:11:01 +08:00
jsh
fa278dec01 add: 周年纪念日 2025-10-12 14:08:16 +08:00
18 changed files with 249 additions and 4 deletions

View File

@@ -1,3 +1,19 @@
drop table if exists `user`
create table user
(
id int unsigned auto_increment
primary key,
create_time datetime null,
update_time datetime null,
username varchar(100) not null,
password varchar(255) not null,
nickname varchar(100) null
)
comment '用户表';
drop table if exists `goal`; drop table if exists `goal`;
CREATE TABLE if not exists `goal` CREATE TABLE if not exists `goal`
@@ -34,8 +50,9 @@ create table habit_record
id int unsigned auto_increment, id int unsigned auto_increment,
create_time datetime null, create_time datetime null,
update_time datetime null, update_time datetime null,
name varchar(100) not null,
date date not null comment '重要的日期', date date not null comment '重要的日期',
type enum ('anniversary', 'commemoration') default 'anniversary' not null type enum ('ANNIVERSARY', 'COMMEMORATION') default 'ANNIVERSARY' not null
) )
comment '周年纪念日'; comment '周年纪念日';

View File

@@ -27,7 +27,7 @@
<url/> <url/>
</scm> </scm>
<properties> <properties>
<java.version>21</java.version> <java.version>17</java.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>

View File

@@ -14,6 +14,14 @@ public class AnniversaryController {
this.anniversaryService = anniversaryService; this.anniversaryService = anniversaryService;
} }
/**
* 获取所有周年日和纪念日
*/
@GetMapping
public R get() {
return R.ok(anniversaryService.getAll());
}
@PostMapping @PostMapping
public R add(Anniversary anniversary) { public R add(Anniversary anniversary) {
anniversaryService.save(anniversary); anniversaryService.save(anniversary);

View File

@@ -0,0 +1,28 @@
package com.dota.nexus.controller;
import com.dota.nexus.entity.LoginDTO;
import com.dota.nexus.entity.R;
import com.dota.nexus.service.UserService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("user")
public class UserController {
UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("login")
public R login(LoginDTO loginDTO) throws Exception {
var res = userService.login(loginDTO.username(), loginDTO.password());
if (res==null) {
return R.error("用户不存在或者密码错误");
}
return R.ok(res);
}
}

View File

@@ -8,7 +8,9 @@ import java.time.LocalDate;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class Anniversary extends Entity{ public class Anniversary extends Entity{
private String name;
private LocalDate date; private LocalDate date;
private type; private AnniversaryEnum type;
} }

View File

@@ -0,0 +1,4 @@
package com.dota.nexus.entity;
public record LoginDTO(String username, String password) {
}

View File

@@ -27,8 +27,12 @@ public class R {
return new R(200, "ok", data); return new R(200, "ok", data);
} }
public static R error(String msg){
return new R(500, msg);
}
public static R error(){ public static R error(){
return new R(500, "服务端发生未知错误"); return error("服务端发生未知错误");
} }
public static R unauthorized() { public static R unauthorized() {

View File

@@ -0,0 +1,14 @@
package com.dota.nexus.entity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class User extends Entity{
private String name;
private String password;
private String nickname;
}

View File

@@ -0,0 +1,4 @@
package com.dota.nexus.entity.vo;
public record AnniversaryRecord(String name, String date, int distance) {
}

View File

@@ -0,0 +1,6 @@
package com.dota.nexus.entity.vo;
import java.util.List;
public record AnniversaryVO (List<AnniversaryRecord> anniversaryList, List<AnniversaryRecord> commemorationList){
}

View File

@@ -0,0 +1,9 @@
package com.dota.nexus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dota.nexus.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

View File

@@ -2,6 +2,8 @@ package com.dota.nexus.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.dota.nexus.entity.Anniversary; import com.dota.nexus.entity.Anniversary;
import com.dota.nexus.entity.vo.AnniversaryVO;
public interface AnniversaryService extends IService<Anniversary> { public interface AnniversaryService extends IService<Anniversary> {
AnniversaryVO getAll();
} }

View File

@@ -0,0 +1,9 @@
package com.dota.nexus.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dota.nexus.entity.User;
public interface UserService extends IService<User> {
String login(String username, String password) throws Exception;
}

View File

@@ -2,10 +2,45 @@ package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dota.nexus.entity.Anniversary; import com.dota.nexus.entity.Anniversary;
import com.dota.nexus.entity.AnniversaryEnum;
import com.dota.nexus.entity.vo.AnniversaryRecord;
import com.dota.nexus.entity.vo.AnniversaryVO;
import com.dota.nexus.mapper.AnniversaryMapper; import com.dota.nexus.mapper.AnniversaryMapper;
import com.dota.nexus.service.AnniversaryService; import com.dota.nexus.service.AnniversaryService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
@Service @Service
public class AnniversaryServiceImpl extends ServiceImpl<AnniversaryMapper, Anniversary> implements AnniversaryService { public class AnniversaryServiceImpl extends ServiceImpl<AnniversaryMapper, Anniversary> implements AnniversaryService {
/**
*
*/
@Override
public AnniversaryVO getAll() {
var aList = new ArrayList<AnniversaryRecord>();
var bList = new ArrayList<AnniversaryRecord>();
var res = new AnniversaryVO(aList, bList);
var anniversaries = this.baseMapper.selectList(null);
var now = LocalDate.now();
for (Anniversary anniversary : anniversaries) {
// 周年,变成今年或者明年
if (anniversary.getType() == AnniversaryEnum.ANNIVERSARY) {
LocalDate date = anniversary.getDate();
date = date.withYear(now.getYear());
if (date.isBefore(now)) {
date = date.withYear(now.getYear() + 1);
}
aList.add(new AnniversaryRecord(anniversary.getName(), date.toString(), (int) ChronoUnit.DAYS.between(now, date)));
} else if (anniversary.getType() == AnniversaryEnum.COMMEMORATION) {
bList.add(new AnniversaryRecord(anniversary.getName(), anniversary.getDate().toString(), (int) ChronoUnit.DAYS.between(anniversary.getDate(), now)));
}
}
return res;
}
} }

View File

@@ -0,0 +1,27 @@
package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dota.nexus.entity.User;
import com.dota.nexus.mapper.UserMapper;
import com.dota.nexus.service.UserService;
import com.dota.nexus.util.GlobalMap;
import com.dota.nexus.util.PasswordUtil;
import org.springframework.stereotype.Service;
import java.util.UUID;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
public String login(String username, String password) throws Exception {
var q = new LambdaQueryWrapper<User>();
q.eq(User::getName, username);
var u = this.baseMapper.selectOne(q);
if (u!=null && PasswordUtil.verify(password, u.getPassword())) {
var uuid = UUID.randomUUID().toString();
GlobalMap.put(uuid, u.getId());
return uuid;
}
return null;
}
}

View File

@@ -0,0 +1,16 @@
package com.dota.nexus.util;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class GlobalMap {
private static final Map<String, Object> MAP = new ConcurrentHashMap<>();
public static void put(String k, Object v) {
MAP.put(k,v);
}
public static Object get(String k) {
return MAP.get(k);
}
}

View File

@@ -0,0 +1,47 @@
package com.dota.nexus.util;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
public class PasswordUtil {
public static String encrypt(String password) throws Exception{
var random = new SecureRandom();
var salt = new byte[16];
random.nextBytes(salt);
var spec = new PBEKeySpec(
password.toCharArray(),
salt,
100000,
256
);
var factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
var hash = factory.generateSecret(spec).getEncoded();
return Base64.getEncoder().encodeToString(salt) + ":" + Base64.getEncoder().encodeToString(hash);
}
public static boolean verify(String password, String storedHash) throws Exception {
var parts = storedHash.split(":");
var salt = Base64.getDecoder().decode(parts[0]);
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
100000,
256
);
byte[] testHash = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
.generateSecret(spec).getEncoded();
return parts[1].equals(Base64.getEncoder().encodeToString(testHash));
}
public static void main(String[] args) throws Exception{
var s = "nexus2017";
var pass =encrypt(s);
System.out.println(pass);
System.out.println(pass.length());
System.out.println(verify(s, pass));
}
}

View File

@@ -0,0 +1,13 @@
package com.dota.nexus.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class TokenUtil {
public static Integer CurrentUserId() {
var req = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
String authorization = req.getHeader("Authorization");
var token = authorization.replace("Bearer ", "");
return (Integer) GlobalMap.get(token);
}
}