Compare commits

..

8 Commits

Author SHA1 Message Date
kkunkka
40c2da044a add: 获取未来的重要日子,获取过去的重要日子 2025-10-14 22:45:42 +08:00
kkunkka
8439653082 add: 跨域 2025-10-14 22:00:52 +08:00
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 284 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

@@ -53,6 +53,7 @@
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<optional>true</optional> <optional>true</optional>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@@ -0,0 +1,19 @@
package com.dota.nexus.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedHeaders("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}

View File

@@ -14,9 +14,25 @@ public class AnniversaryController {
this.anniversaryService = anniversaryService; this.anniversaryService = anniversaryService;
} }
/**
* 获取未来所有周年日和纪念日
*/
@GetMapping("future")
public R getFuture() {
return R.ok(anniversaryService.getFuture());
}
/**
* 获取过去的纪念日
*/
@GetMapping("past")
public R getPast() {
return R.ok(anniversaryService.getPast());
}
@PostMapping @PostMapping
public R add(Anniversary anniversary) { public R add(Anniversary anniversary) {
anniversaryService.save(anniversary); anniversaryService.saveOrUpdate(anniversary);
return R.ok(); return R.ok();
} }

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 AnniversaryVO(String name, String date, int distance) {
}

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,12 @@ 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;
import java.util.List;
public interface AnniversaryService extends IService<Anniversary> { public interface AnniversaryService extends IService<Anniversary> {
List<AnniversaryVO> getFuture();
List<AnniversaryVO> getPast();
} }

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

@@ -1,11 +1,55 @@
package com.dota.nexus.service.impl; package com.dota.nexus.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.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;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@Service @Service
public class AnniversaryServiceImpl extends ServiceImpl<AnniversaryMapper, Anniversary> implements AnniversaryService { public class AnniversaryServiceImpl extends ServiceImpl<AnniversaryMapper, Anniversary> implements AnniversaryService {
@Override
public List<AnniversaryVO> getFuture() {
var anniversaries = this.baseMapper.selectList(null);
var list = new ArrayList<AnniversaryVO>();
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);
}
list.add(new AnniversaryVO(anniversary.getName(), date.toString(), (int) ChronoUnit.DAYS.between(now, date)));
} else if (anniversary.getType() == AnniversaryEnum.COMMEMORATION && !anniversary.getDate().isBefore(now)) {
list.add(new AnniversaryVO(anniversary.getName(), anniversary.getDate().toString(), (int) ChronoUnit.DAYS.between(now, anniversary.getDate())));
}
}
list.sort(Comparator.comparingInt(AnniversaryVO::distance));
return list;
}
@Override
public List<AnniversaryVO> getPast() {
var q = new LambdaQueryWrapper<Anniversary>();
q.eq(Anniversary::getType, AnniversaryEnum.COMMEMORATION);
var anniversaries = this.baseMapper.selectList(q);
var now = LocalDate.now();
return anniversaries.stream().map(a -> new AnniversaryVO(a.getName(), a.getDate().toString(), (int) ChronoUnit.DAYS.between(now, a.getDate()))).sorted((a,b)->b.distance()-a.distance()).collect(Collectors.toList());
}
} }

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