diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 66bc19f..65d1d7f 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -10,10 +10,14 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml index dfc8d74..6c28734 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -2,5 +2,7 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 5ac9743..7f69666 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,8 +5,14 @@ + diff --git a/.idea/webContexts.xml b/.idea/webContexts.xml new file mode 100644 index 0000000..209b90b --- /dev/null +++ b/.idea/webContexts.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/backend/pom.xml b/backend/pom.xml index fe28dcb..e5fa914 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -5,43 +5,27 @@ org.springframework.boot spring-boot-starter-parent - 3.3.5 - + 3.1.5 + - org.example + com backend 0.0.1-SNAPSHOT backend backend - - - - - - - - - - - - - 17 - - org.springframework.boot - spring-boot-starter-data-jdbc - org.springframework.boot spring-boot-starter-web + - javax.persistence - javax.persistence-api - 2.2 + org.mybatis.spring.boot + mybatis-spring-boot-starter + 3.0.0 @@ -49,20 +33,47 @@ mysql-connector-j runtime + org.projectlombok lombok true + + + org.springframework.boot + spring-boot-starter-validation + + + + com.auth0 + java-jwt + 4.4.0 + + org.springframework.boot spring-boot-starter-test test + + + com.aliyun.oss + aliyun-sdk-oss + 3.17.0 + + org.springframework.boot - spring-boot-starter-data-jpa + spring-boot-starter-data-redis + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.4.6 + + diff --git a/backend/src/main/java/com/backend/Application.java b/backend/src/main/java/com/backend/Application.java new file mode 100644 index 0000000..5386c8c --- /dev/null +++ b/backend/src/main/java/com/backend/Application.java @@ -0,0 +1,11 @@ +package com.backend; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/backend/src/main/java/com/backend/config/WebConfig.java b/backend/src/main/java/com/backend/config/WebConfig.java new file mode 100644 index 0000000..f5a791f --- /dev/null +++ b/backend/src/main/java/com/backend/config/WebConfig.java @@ -0,0 +1,25 @@ +package com.backend.config; + +import com.backend.interceptor.LoginInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + private static final List BYPASS_PATHS = List.of( + "/user/login", + "/user/register"); + + @Autowired + private LoginInterceptor loginInterceptor; + + @Override + public void addInterceptors(final InterceptorRegistry registry) { + // For login and register, not intercept. + registry.addInterceptor(loginInterceptor).excludePathPatterns(BYPASS_PATHS); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/backend/controller/UserController.java b/backend/src/main/java/com/backend/controller/UserController.java new file mode 100644 index 0000000..5f0835d --- /dev/null +++ b/backend/src/main/java/com/backend/controller/UserController.java @@ -0,0 +1,119 @@ +package com.backend.controller; + +import com.backend.pojo.Result; +import com.backend.pojo.User; +import com.backend.service.UserService; +import com.backend.utils.JwtUtil; +import com.backend.utils.Md5Util; +import com.backend.utils.ThreadLocalUtil; +import jakarta.validation.constraints.Pattern; +import org.hibernate.validator.constraints.URL; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.util.StringUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.time.Duration; +import java.util.Map; + +import static com.backend.interceptor.LoginInterceptor.AUTHORIZATION_HEADER; + +@RestController +@RequestMapping("/user") +@Validated +public class UserController { + + @Autowired + private UserService userService; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @PostMapping("/register") + public Result register(@Pattern(regexp = "^\\S{5,16}$") final String username, @Pattern(regexp = "^\\S{5,16}$") final String password) { + final User existingUser = userService.findByUsername(username); + if (existingUser == null) { + userService.register(username, password); + return Result.success(); + } else { + return Result.error("用户名已被占用"); + } + } + + @PostMapping("/login") + public Result login(@Pattern(regexp = "^\\S{5,16}$") final String username, @Pattern(regexp = "^\\S{5,16}$") final String password) { + final User existingUser = userService.findByUsername(username); + if (existingUser == null) { + return Result.error("用户不存在"); + } + if (Md5Util.getMD5String(password).equals(existingUser.getPassword())) { + final Map map = Map.of("id", existingUser.getId(), + "username", existingUser.getUsername()); + final String token = JwtUtil.genToken(map); + // Save token to redis + final ValueOperations operations = stringRedisTemplate.opsForValue(); + // If key is token, and when we validate, and the token doesn't exist, then it has expired. + operations.set(token, token, Duration.ofHours(12)); + // Return JWT token + return Result.success(token); + } else { + return Result.error("密码错误"); + } + } + + @GetMapping("/userInfo") + public Result userInfo() { + + final Map map = ThreadLocalUtil.get(); + final String username = (String) map.get("username"); + final User user = userService.findByUsername(username); + return Result.success(user); + } + + @PutMapping("/update") + public Result update(@RequestBody @Validated final User user) { + final Map map = ThreadLocalUtil.get(); + final Integer id = (Integer) map.get("id"); + if (user.getId().equals(id)) { + userService.update(user); + return Result.success(); + } else { + return Result.error("非本人id"); + } + } + + @PatchMapping("/updateAvatar") + public Result updateAvatar(@RequestParam @URL final String avatarUrl) { + userService.updateAvatar(avatarUrl); + return Result.success(); + } + + @PatchMapping("/updatePwd") + public Result updatePwd(@RequestBody Map params, @RequestHeader(AUTHORIZATION_HEADER) final String token) { + final String oldPwd = params.get("old_pwd"); + final String newPwd = params.get("new_pwd"); + final String rePwd = params.get("re_pwd"); + if (!StringUtils.hasLength(oldPwd) || !StringUtils.hasLength(newPwd) || !StringUtils.hasLength(rePwd)) { + return Result.error("缺少必要的参数"); + } + + final Map map = ThreadLocalUtil.get(); + final String username = (String) map.get("username"); + final User user = userService.findByUsername(username); + if (!rePwd.equals(newPwd)) { + return Result.error("两次结果不一样"); + } + if (!user.getPassword().equals(Md5Util.getMD5String(oldPwd))) { + return Result.error("密码填写不正确"); + } + + userService.updatePwd(newPwd); + // Delete token in redis. + final ValueOperations operations = stringRedisTemplate.opsForValue(); + operations.getOperations().delete(token); + + return Result.success(); + } + } diff --git a/backend/src/main/java/com/backend/exception/GlobalExceptionHandler.java b/backend/src/main/java/com/backend/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..9d802a9 --- /dev/null +++ b/backend/src/main/java/com/backend/exception/GlobalExceptionHandler.java @@ -0,0 +1,16 @@ +package com.backend.exception; + +import com.backend.pojo.Result; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler({Exception.class}) + public Result handleException(final Exception exception) { + exception.printStackTrace(); + return Result.error(StringUtils.hasLength(exception.getMessage()) ? exception.getMessage() : "操作失败"); + } +} diff --git a/backend/src/main/java/com/backend/interceptor/LoginInterceptor.java b/backend/src/main/java/com/backend/interceptor/LoginInterceptor.java new file mode 100644 index 0000000..c980a3d --- /dev/null +++ b/backend/src/main/java/com/backend/interceptor/LoginInterceptor.java @@ -0,0 +1,45 @@ +package com.backend.interceptor; + +import com.backend.utils.JwtUtil; +import com.backend.utils.ThreadLocalUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.util.Map; + +@Component +public class LoginInterceptor implements HandlerInterceptor { + public static final String AUTHORIZATION_HEADER = "Authorization"; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + @Override + public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) { + final String token = request.getHeader(AUTHORIZATION_HEADER); + try { + // Get same token from redis. + final ValueOperations operations = stringRedisTemplate.opsForValue(); + final String redisToken = operations.get(token); + if (redisToken == null) { // Token has expired + throw new RuntimeException("过期或未登录"); + } + final Map map = JwtUtil.parseToken(token); + ThreadLocalUtil.set(map); + return true; + } catch (Exception e) { + response.setStatus(401); + return false; + } + } + + @Override + public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final Exception ex) throws Exception { + ThreadLocalUtil.remove(); + } +} diff --git a/backend/src/main/java/com/backend/mapper/UserMapper.java b/backend/src/main/java/com/backend/mapper/UserMapper.java new file mode 100644 index 0000000..9557b45 --- /dev/null +++ b/backend/src/main/java/com/backend/mapper/UserMapper.java @@ -0,0 +1,24 @@ +package com.backend.mapper; + +import com.backend.pojo.User; +import org.apache.ibatis.annotations.*; + +@Mapper +public interface UserMapper { + + @Insert("insert into user(username, password, create_time, update_time) " + + "values(#{username},#{md5String},now(),now())") + void add(final String username, final String md5String); + + @Select("select * from user where username=#{username}") + User findByUsername(final String username); + + @Update("update user set nickname=#{nickname}, update_time=now() where id=#{id}") + void update(final User user); + + @Update("update user set user_pic=#{url}, update_time=now() where id=#{id}") + void updateAvatar(final String url, final Integer id); + + @Update("update user set password=#{md5String}, update_time=now() where id=#{id}") + void updatePwd(final String md5String, final Integer id); +} diff --git a/backend/src/main/java/com/backend/pojo/Result.java b/backend/src/main/java/com/backend/pojo/Result.java new file mode 100644 index 0000000..e242b7e --- /dev/null +++ b/backend/src/main/java/com/backend/pojo/Result.java @@ -0,0 +1,28 @@ +package com.backend.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +public class Result { + private Integer code;//业务状态码 0-成功 1-失败 + private String message;//提示信息 + private T data;//响应数据 + + //快速返回操作成功响应结果(带响应数据) + public static Result success(T 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); + } +} diff --git a/backend/src/main/java/com/backend/pojo/User.java b/backend/src/main/java/com/backend/pojo/User.java new file mode 100644 index 0000000..8ddc6ac --- /dev/null +++ b/backend/src/main/java/com/backend/pojo/User.java @@ -0,0 +1,26 @@ +package com.backend.pojo; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class User { + @NotNull + private Integer id;//主键ID + private String username;//用户名 + @JsonIgnore // let springmvc ignore password when converting object to json + private String password;//密码 + @NotEmpty + @Pattern(regexp = "^\\S{1,10}$") + private String nickname;//昵称 + private String userPic;//用户头像地址 + private LocalDateTime createTime;//创建时间 + private LocalDateTime updateTime;//更新时间 +} diff --git a/backend/src/main/java/com/backend/service/UserService.java b/backend/src/main/java/com/backend/service/UserService.java new file mode 100644 index 0000000..b0cf244 --- /dev/null +++ b/backend/src/main/java/com/backend/service/UserService.java @@ -0,0 +1,15 @@ +package com.backend.service; + +import com.backend.pojo.User; + +public interface UserService { + User findByUsername(final String username); + + void register(final String username, final String password); + + void update(final User user); + + void updateAvatar(final String url); + + void updatePwd(final String newPwd); +} diff --git a/backend/src/main/java/com/backend/service/impl/UserServiceImpl.java b/backend/src/main/java/com/backend/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..6de1825 --- /dev/null +++ b/backend/src/main/java/com/backend/service/impl/UserServiceImpl.java @@ -0,0 +1,49 @@ +package com.backend.service.impl; + +import com.backend.mapper.UserMapper; +import com.backend.pojo.User; +import com.backend.service.UserService; +import com.backend.utils.Md5Util; +import com.backend.utils.ThreadLocalUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserMapper userMapper; + + @Override + public User findByUsername(final String username) { + return userMapper.findByUsername(username); + } + + @Override + public void register(final String username, final String password) { + final String md5String = Md5Util.getMD5String(password); + userMapper.add(username, md5String); + } + + @Override + public void update(final User user) { + userMapper.update(user); + } + + @Override + public void updateAvatar(final String url) { + final Map map = ThreadLocalUtil.get(); + final Integer id = (Integer) map.get("id"); + userMapper.updateAvatar(url, id); + } + + @Override + public void updatePwd(final String newPwd) { + final String md5String = Md5Util.getMD5String(newPwd); + final Map map = ThreadLocalUtil.get(); + final Integer id = (Integer) map.get("id"); + userMapper.updatePwd(md5String, id); + } +} diff --git a/backend/src/main/java/com/backend/utils/AliOssUtil.java b/backend/src/main/java/com/backend/utils/AliOssUtil.java new file mode 100644 index 0000000..1b432ef --- /dev/null +++ b/backend/src/main/java/com/backend/utils/AliOssUtil.java @@ -0,0 +1,46 @@ +package com.backend.utils; + +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.OSSException; + +import java.io.InputStream; + +public class AliOssUtil { + private static final String ENDPOINT = "https://oss-cn-beijing.aliyuncs.com"; + public static final String ACCESS_KEY_ID = System.getenv("ALIYUN_ACCESSKEY_ID"); + private static final String SECRET_ACCESS_KEY = System.getenv("ALIYUN_ACCESSKEY_SECRET"); + private static final String BUCKET_NAME = "big-event-1"; + + //上传文件,返回文件的公网访问地址 + public static String uploadFile(String objectName, InputStream inputStream) { + // 创建OSSClient实例。 + OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, SECRET_ACCESS_KEY); + //公文访问地址 + String url = ""; + try { + // 创建存储空间。 + ossClient.createBucket(BUCKET_NAME); + ossClient.putObject(BUCKET_NAME, objectName, inputStream); + url = "https://" + BUCKET_NAME + "." + ENDPOINT.substring(ENDPOINT.lastIndexOf("/") + 1) + "/" + objectName; + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return url; + } +} diff --git a/backend/src/main/java/com/backend/utils/JwtUtil.java b/backend/src/main/java/com/backend/utils/JwtUtil.java new file mode 100644 index 0000000..49328dc --- /dev/null +++ b/backend/src/main/java/com/backend/utils/JwtUtil.java @@ -0,0 +1,29 @@ +package com.backend.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; + +import java.util.Date; +import java.util.Map; + +public class JwtUtil { + + private static final String KEY = "express-jwt-secret"; + + //接收业务数据,生成token并返回 + public static String genToken(Map claims) { + return JWT.create() + .withClaim("claims", claims) + .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)) + .sign(Algorithm.HMAC256(KEY)); + } + + //接收token,验证token,并返回业务数据 + public static Map parseToken(String token) { + return JWT.require(Algorithm.HMAC256(KEY)) + .build() + .verify(token) + .getClaim("claims") + .asMap(); + } +} diff --git a/backend/src/main/java/com/backend/utils/Md5Util.java b/backend/src/main/java/com/backend/utils/Md5Util.java new file mode 100644 index 0000000..810c227 --- /dev/null +++ b/backend/src/main/java/com/backend/utils/Md5Util.java @@ -0,0 +1,73 @@ +package com.backend.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); + } + +} diff --git a/backend/src/main/java/com/backend/utils/ThreadLocalUtil.java b/backend/src/main/java/com/backend/utils/ThreadLocalUtil.java new file mode 100644 index 0000000..3366629 --- /dev/null +++ b/backend/src/main/java/com/backend/utils/ThreadLocalUtil.java @@ -0,0 +1,26 @@ +package com.backend.utils; + +/** + * ThreadLocal 工具类 + */ +@SuppressWarnings("all") +public class ThreadLocalUtil { + //提供ThreadLocal对象, + private static final ThreadLocal THREAD_LOCAL = new ThreadLocal(); + + //根据键获取值 + public static T get() { + return (T) THREAD_LOCAL.get(); + } + + //存储键值对 + public static void set(Object value) { + THREAD_LOCAL.set(value); + } + + + //清除ThreadLocal 防止内存泄漏 + public static void remove() { + THREAD_LOCAL.remove(); + } +} diff --git a/backend/src/main/java/org/example/backend/BackendApplication.java b/backend/src/main/java/org/example/backend/BackendApplication.java deleted file mode 100644 index 5b6f6d8..0000000 --- a/backend/src/main/java/org/example/backend/BackendApplication.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.example.backend; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@SpringBootApplication -@RestController -public class BackendApplication { - - @RequestMapping("/") - public String hello() { - return "Hello, World!"; - } - public static void main(String[] args) { - SpringApplication.run(BackendApplication.class, args); - } -} diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml new file mode 100644 index 0000000..bb0cf30 --- /dev/null +++ b/backend/src/main/resources/application-dev.yml @@ -0,0 +1,16 @@ +spring: + datasource: + url: jdbc:mysql://localhost:3306/express_management + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: 123456 + data: + redis: + host: 47.115.225.58 + port: 6379 +mybatis: + configuration: + map-underscore-to-camel-case: true +#mybatis: +# mapper-locations: classpath:./mapper/*.xml +# type-aliases-package: com.backend.pojo \ No newline at end of file diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties deleted file mode 100644 index 2966c80..0000000 --- a/backend/src/main/resources/application.properties +++ /dev/null @@ -1,7 +0,0 @@ -spring.application.name=backend -server.port=8888 -spring.datasource.url=jdbc:mysql://localhost:3306/express_management -spring.datasource.username=root -spring.datasource.password=123456 -spring.jpa.hibernate.ddl-auto=update -spring.jpa.show-sql=true \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml new file mode 100644 index 0000000..3d7808a --- /dev/null +++ b/backend/src/main/resources/application.yml @@ -0,0 +1,3 @@ +spring: + profiles: + active: dev diff --git a/backend/src/main/resources/com.backend.mapper/UserMapper.xml b/backend/src/main/resources/com.backend.mapper/UserMapper.xml new file mode 100644 index 0000000..63342d3 --- /dev/null +++ b/backend/src/main/resources/com.backend.mapper/UserMapper.xml @@ -0,0 +1,37 @@ + + + + + + INSERT INTO user (username, password, create_time, update_time) + VALUES (#{username}, #{md5String}, NOW(), NOW()) + + + + + + UPDATE user + SET nickname = #{nickname}, + update_time = NOW() + WHERE id = #{id} + + + + UPDATE user + SET user_pic = #{url}, + update_time = NOW() + WHERE id = #{id} + + + + UPDATE user + SET password = #{md5String}, + update_time = NOW() + WHERE id = #{id} + + + diff --git a/backend/src/main/resources/mapper/UserMapper.xml b/backend/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..63342d3 --- /dev/null +++ b/backend/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,37 @@ + + + + + + INSERT INTO user (username, password, create_time, update_time) + VALUES (#{username}, #{md5String}, NOW(), NOW()) + + + + + + UPDATE user + SET nickname = #{nickname}, + update_time = NOW() + WHERE id = #{id} + + + + UPDATE user + SET user_pic = #{url}, + update_time = NOW() + WHERE id = #{id} + + + + UPDATE user + SET password = #{md5String}, + update_time = NOW() + WHERE id = #{id} + + + diff --git a/backend/src/test/java/org/example/backend/BackendBackendApplicationTests.java b/backend/src/test/java/com/backend/BackendApplicationTests.java similarity index 70% rename from backend/src/test/java/org/example/backend/BackendBackendApplicationTests.java rename to backend/src/test/java/com/backend/BackendApplicationTests.java index 92ecd03..d427c41 100644 --- a/backend/src/test/java/org/example/backend/BackendBackendApplicationTests.java +++ b/backend/src/test/java/com/backend/BackendApplicationTests.java @@ -1,10 +1,10 @@ -package org.example.backend; +package com.backend; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -class BackendBackendApplicationTests { +class BackendApplicationTests { @Test void contextLoads() { diff --git a/frontend/package.json b/frontend/package.json index 83baf01..bcc2437 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "lesson1_vite", + "name": "express", "private": true, "version": "0.0.0", "type": "module", @@ -9,16 +9,21 @@ "preview": "vite preview" }, "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "@vueup/vue-quill": "^1.2.0", "axios": "1.2.1", "element-plus": "^2.8.6", "express": "^4.21.1", "pinia": "2.0.27", + "pinia-persistedstate-plugin": "^0.1.0", "save": "^2.9.0", + "scss": "^0.2.4", "vue": "^3.4.37", "vue-router": "4" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.2", + "sass": "^1.81.0", "vite": "^5.4.1" } } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index d2993ee..0c2d3f3 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -8,16 +8,5 @@ diff --git a/frontend/src/View/Page2.vue b/frontend/src/View/Layout.vue similarity index 59% rename from frontend/src/View/Page2.vue rename to frontend/src/View/Layout.vue index 9cd9eb6..f79cdd8 100644 --- a/frontend/src/View/Page2.vue +++ b/frontend/src/View/Layout.vue @@ -1,9 +1,11 @@ + + - + \ No newline at end of file diff --git a/frontend/src/View/Login.vue b/frontend/src/View/Login.vue index 7128e05..9e87297 100644 --- a/frontend/src/View/Login.vue +++ b/frontend/src/View/Login.vue @@ -1,72 +1,177 @@ - - +import {Lock, User} from "@element-plus/icons-vue" +import {ref} from "vue"; +import {userLoginService, userRegisterService} from "@/api/user"; +import {ElMessage} from "element-plus"; +import {useRouter} from "vue-router"; +import {useTokenStore} from "@/stores/token"; + +// Register page and Login page use the same view. +// By default, show login. +const isRegister = ref(false); +const registerData = ref({ + username: '', + password: '', + rePassword: '' +}); - + \ No newline at end of file diff --git a/frontend/src/View/Page1.vue b/frontend/src/View/Page1.vue deleted file mode 100644 index 9f19e8f..0000000 --- a/frontend/src/View/Page1.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - - - \ No newline at end of file diff --git a/frontend/src/View/Register.vue b/frontend/src/View/Register.vue deleted file mode 100644 index 1658b45..0000000 --- a/frontend/src/View/Register.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - - - diff --git a/frontend/src/View/user/MyInfo.vue b/frontend/src/View/user/MyInfo.vue index 305323d..b6ad80a 100644 --- a/frontend/src/View/user/MyInfo.vue +++ b/frontend/src/View/user/MyInfo.vue @@ -1,3 +1,4 @@ +