1.编写配置文件 在项目中,我们需要对项目的数据库地址,redis地址,和服务的端口进行配置就需要进行配置文件的编写,让我们可以控制整个项目在
的resources中,已经存在一个配置文件,我们可以用它来进行配置文件的编写,但是由于我的习惯问题,我习惯使用yml文件进行配置,这两种文件格式在配置上没有本质区别,但在语法上有一定的区别
1.1配置运行端口 在我们的项目运行中,我们可以制定项目的运行端口,以便于我们对其进行访问,打开application.properties进行配置文件的编写,打开文件,我们发现里面已经存在一条语句,这条语句,用于制定,这个服务的名字,可以保留,也可以删除
现在我们进行端口的更换,在我们tomcat服务器中,默认端口是8080,但是由于8080端口太过于常见,容易发生一些问题,所以我们需要进行端口更换,当然,我们也可以不进行更换,
当8080端口已经被应占用时,tomcat服务器启动失败,这时候就需要更换端口
对于application.properties我们需要这条语句
就可以改变运行端口,重新启动项目,发现项目的端口已经改变
现在我们已经改变了端口,可以进行愉快的开发了
2.登陆注册 2.1一个测试 在一个后台项目中,最重要的就是登陆和注册,我们需要对登陆是人进行校验,防止越权访问,在根包名下建立一个软件包,包名为controller
在包下建立一个java文件,文件名为UserController
首先,由于我们使用spring进行开发,我们要将所有的包交给spring来管理,这是一个controller类,所以,我们要在文件中加入
告诉spring,这是一个请求入口。
现在这个接口就可以将请求传入此处进行处理
在文件中随便创建一个请求,我们来进行测试一下
1 2 3 4 5 6 7 8 @RestController public class UserController { @GetMapping("/hello") public String Hello () { return "Hello World" ; } }
这串代码的意思就是,当请求进来的时候,如果请求的路径是(/hello)那我就将helloword返回回去,现在我们重新启动项目
我们可以看到,当访问/hello的时候,浏览器向本地发送了一个请求,请求路径正好是hello,这样,我们的后端便可以收到这个请求,然后后端给我们返回了helloword,浏览器将helloword打印在了浏览器上
2.2正式开写
通过这个测试,我们大概明白了请求的原理,以及为什么会收到请求,并且返回数据
众所周知,要想登陆,我们需要注册一个账号,那么我们就以注册开始吧
2.2.1注册 查看接口文档
注册
基本信息
请求路径:/user/register
请求方式:POST
接口描述:该接口用于注册新用户
请求参数
请求参数格式:x-www-form-urlencoded
请求参数说明:
参数名称
说明
类型
是否必须
备注
username
用户名
string
是
5~16位非空字符
password
密码
string
是
5~16位非空字符
请求数据样例:
1 username=zhangsan&password=123456
我们发现,想要注册,我们需要向后端发送请求,我们需要告诉服务器我们的信息,这样我们才可以注册成功,那我们就要接受这些参数,那我们就可以开始编写代码
1 2 3 4 5 @PostMapping("/register") public String register (String username, String password) { System.out.println("UserName" +username + "password " + password); return "注册成功" ; }
这段代码中,我们通过String参数来接受我们的用户名和密码,然后我们打印了用户名和密码,并且返回了注册成功,现在我们来测试一下
测试时,以前我们使用postman,这个比较麻烦,我们现在使用apifox,这个软件现在有了idea插件,我们进行安装
安装后,我们可以在idea的右侧边栏找到apifox已经自动识别了我们的接口
我们自定义一下用户名和密码就可以进行模拟请求测试
重新启动项目,让我们刚刚编写的代码生效,我们随便输入点数,可以看到我们已经成功的发送了请求,也返回了注册成功
好的,这样我们已经注册成功了,但是,我们不能把登陆信息写死在代码里面,所以我们需要将我们注册的账号和密码存储进数据库,这样在多用户登陆的时候能直接进行查询并且验证密码,要想进行数据库的读写,首先要对,数据库进行配置
在项目的配置文件pom.xml文件中,已经存在了mysql的倚赖,由于我们使用的是springboot项目不需要复杂的配置就可以使用,要是倚赖中没有mysql倚赖,现在进行添加
1 2 3 4 5 <dependency > <groupId > com.mysql</groupId > <artifactId > mysql-connector-j</artifactId > <scope > runtime</scope > </dependency >
然后我们需要在项目配置文件中设置数据库的链接ip和账号密码,
1 2 3 4 spring.datasource.url=jdbc:mysql://localhost:3306/news spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
这样不出意外我们就可以访问到数据库了,但是这样如果数据库没有链接则会报错,我们定义一个启动类来监控数据库的状态
在src/main/java/com/dreamxiao/newbackend/InitRun.java下创建文件,用于链接数据库,但是仅仅靠Java中自带的log记录,我们很难发现问题,所以我们要引入其他的log记录工具,这里我们使用@slf4j里面的log记录工具,但是在一开始我们已经导入了lombok而@slf4j是里面的一个包,所以我们可以直接使用,在刚刚新建的文件中写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.dreamxiao.newbackend;import jakarta.annotation.Resource;import lombok.extern.slf4j.Slf4j;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.ApplicationArguments;import org.springframework.boot.ApplicationRunner;import org.springframework.stereotype.Component;import javax.sql.DataSource;import java.sql.SQLException;@Slf4j @Component("initRun") public class InitRun implements ApplicationRunner { private static final Logger logger = LoggerFactory.getLogger(InitRun.class); @Resource private DataSource dataSource; @Override public void run (ApplicationArguments args) { try { dataSource.getConnection(); logger.error("服务启动成功,可以开始愉快的开发了" ); } catch (SQLException e) { logger.error("数据库配置错误,请检查数据库配置" ); } catch (Exception e) { logger.error("服务启动失败" , e); } } }
现在还没有合适的jdbc组件,我们在springboot文件中,习惯使用mybatis进行数据库的访问,现在在项目中添加这个倚赖
1 2 3 4 5 <dependency > <groupId > org.mybatis.spring.boot</groupId > <artifactId > mybatis-spring-boot-starter</artifactId > <version > 3.0.3</version > </dependency >
现在启动项目,不出意外,现在项目应该能正确的启动并且在控制台打印出链接数据库成功
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.5.3) 2025-08-01T18:42:21.372+08:00 INFO 16808 --- [newBackEnd] [ main] c.d.newbackend.NewBackEndApplication : Starting NewBackEndApplication using Java 21.0.6 with PID 16808 (C:\web\java\newBackEnd\target\classes started by DREAMXIAOSHEN in C:\web\java\newBackEnd) 2025-08-01T18:42:21.373+08:00 INFO 16808 --- [newBackEnd] [ main] c.d.newbackend.NewBackEndApplication : No active profile set, falling back to 1 default profile: "default" 2025-08-01T18:42:21.787+08:00 WARN 16808 --- [newBackEnd] [ main] o.m.s.mapper.ClassPathMapperScanner : No MyBatis mapper was found in '[com.dreamxiao.newbackend]' package. Please check your configuration. 2025-08-01T18:42:21.961+08:00 INFO 16808 --- [newBackEnd] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8081 (http) 2025-08-01T18:42:21.970+08:00 INFO 16808 --- [newBackEnd] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2025-08-01T18:42:21.971+08:00 INFO 16808 --- [newBackEnd] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.42] 2025-08-01T18:42:22.000+08:00 INFO 16808 --- [newBackEnd] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2025-08-01T18:42:22.000+08:00 INFO 16808 --- [newBackEnd] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 596 ms 2025-08-01T18:42:22.321+08:00 INFO 16808 --- [newBackEnd] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8081 (http) with context path '/' 2025-08-01T18:42:22.327+08:00 INFO 16808 --- [newBackEnd] [ main] c.d.newbackend.NewBackEndApplication : Started NewBackEndApplication in 1.229 seconds (process running for 1.606) 2025-08-01T18:42:22.330+08:00 INFO 16808 --- [newBackEnd] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2025-08-01T18:42:22.562+08:00 INFO 16808 --- [newBackEnd] [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@2d206a71 2025-08-01T18:42:22.563+08:00 INFO 16808 --- [newBackEnd] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2025-08-01T18:42:22.565+08:00 ERROR 16808 --- [newBackEnd] [ main] com.dreamxiao.newbackend.InitRun : 服务启动成功,可以开始愉快的开发了
可以看到,数据库成功的启动,现在我们需要编写接口来进行数据库的访问
2.2.2注册信息写入数据库 springboot中,具有三层架构,controller,service,mapper,第一个是请求的接入口,第二个一般是数据处理,第三个一般是数据库访问,现在我们需要创建这些文件
按照这样创建文件
在文件中写入
mapper中
1 2 3 4 5 6 7 8 package com.dreamxiao.newbackend.mapper;import org.apache.ibatis.annotations.Mapper;@Mapper public interface UserMapper {}
service中
1 2 3 4 5 6 package com.dreamxiao.newbackend.service;public interface UserService {}
serviceimpl中
1 2 3 4 5 6 7 8 9 10 package com.dreamxiao.newbackend.service.impl;import com.dreamxiao.newbackend.service.UserService;import org.springframework.stereotype.Service;@Service public class UserServiceImpl implements UserService {}
现在回到controller中
将service注入其中
1 2 3 @Resource private UserService userService;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @RestController public class UserController { @Resource private UserService userService; @PostMapping("/register") public String register (String username, String password) { userService.register(username, password); System.out.println("UserName" + username + "password " + password); return "注册成功" ; } }
使用service接受请求,在service中创建此方法
1 2 3 4 5 6 7 package com.dreamxiao.newbackend.service;public interface UserService { void register (String username, String password) ; }
在impl中实现方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.dreamxiao.newbackend.service.impl;import com.dreamxiao.newbackend.service.UserService;import org.springframework.stereotype.Service;@Service public class UserServiceImpl implements UserService { @Override public void register (String username, String password) { } }
现在我们就可以再将mapper注入到service中,操作数据库
1 2 3 4 5 6 7 8 9 10 11 12 @Service public class UserServiceImpl implements UserService { @Resource private UserMapper userMapper; @Override public void register (String username, String password) { userMapper.register(username, password); } }
在mapper中实现方法并且操作数据库,编写sql命令
1 2 3 4 5 6 7 @Mapper public interface UserMapper { @Insert("insert into user (username, password) values (#{username}, #{password})") void register (String username, String password) ; }
运行项目,发送请求,观察数据库
不出意外,我们将会报错,因为在数据库中,创建时间和更新时间是默认不为空的,我们需要在插入数据的时候创建时间和更新时间一起插入进去,修改数据库插语句
1 2 3 4 5 6 7 8 9 10 11 12 package com.dreamxiao.newbackend.mapper;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Mapper;@Mapper public interface UserMapper { @Insert("insert into user (username, password, create_time, update_time) VALUES (#{username},#{password},now(),now())") void register (String username, String password) ; }
现在重新运行
观察数据库
发现数据已经成功插入
现在我们观察返回的数据,现在我们返回的是注册成功这四个字,但是如果返回的是这四个字,我们的前端,不好进行数据处理,所以我们要规范返回数据的格式
在包下创建pojo文件夹,里面创建一个result文件
文件结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 C:. └─newbackend │ InitRun.java │ NewBackEndApplication.java │ ├─controller │ UserController.java │ ├─mapper │ UserMapper.java │ ├─pojo │ Result.java │ └─service │ UserService.java │ └─impl UserServiceImpl.java
文件中写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package com.dreamxiao.newbackend.pojo;public class Result <T> { private Integer code; private String message; private T data; public Result () { } public Result (Integer code, String message, T data) { this .code = code; this .data = data; this .message = message; } public Integer getCode () { return code; } public void setCode (Integer code) { this .code = code; } public String getMessage () { return message; } public void setMessage (String message) { this .message = message; } public T getData () { return data; } public void setData (T data) { this .data = 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 ); } }
修改注册请求,将其改为标准返回数据
1 2 3 4 5 { "code" : 0 , "message" : "操作成功" , "data" : "注册成功" }
由于密码是明文存储,导致在数据库中存储极其不安全,所以我们对密码进行md5加密,增加密码的安全性,我们新建一个utils文件夹,在里面放入stringtools用来存放相关工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.dreamxiao.newbackend.utils;import org.apache.commons.codec.digest.DigestUtils;public class StringTools { public static String encodeByMD5 (String originString) { return StringTools.isEmpty(originString) ? null : DigestUtils.md5Hex(originString); } public static boolean isEmpty (String str) { if (null == str || str.isEmpty() || "null" .equals(str) || "\u0000" .equals(str)) { return true ; } else return str.trim().isEmpty(); } }
在配置文件中导入相关倚赖
1 2 3 4 5 6 7 8 9 10 11 12 13 <dependency > <groupId > org.apache.commons</groupId > <artifactId > commons-lang3</artifactId > <version > 3.18.0</version > </dependency > <dependency > <groupId > org.apache.commons</groupId > <artifactId > commons-compress</artifactId > <version > 1.26.2</version > </dependency >
文件tree为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 C:. └─newbackend │ InitRun.java │ NewBackEndApplication.java │ ├─controller │ UserController.java │ ├─mapper │ UserMapper.java │ ├─pojo │ Result.java │ ├─service │ │ UserService.java │ │ │ └─impl │ UserServiceImpl.java │ └─utils StringTools.java
现在我们对密码的存储进行相关改动,将密码加密后存储进数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Service public class UserServiceImpl implements UserService { @Resource private UserMapper userMapper; @Override public void register (String username, String password) { String md5password = StringTools.encodeByMD5(password); userMapper.register(username, md5password); } }
重新启动项目,测试
密码已经成功加密
2.3登陆 现在你大概已经会了开发的相关步骤,以下内容将不再解析,但代码会有注释,都是一个原理
导入jwt的相关倚赖,用来给后端返回token,token用来验证登陆状态
1 2 3 4 5 6 <dependency > <groupId > com.auth0</groupId > <artifactId > java-jwt</artifactId > <version > 4.3.0</version > </dependency >
在utils下创建jwt的工具类 用来生成和验证jwt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.dreamxiao.newbackend.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 = "forexample" ; public static String genToken (Map<String, Object> claims) { return JWT.create() .withClaim("claims" , claims) .withExpiresAt(new Date (System.currentTimeMillis() + 1000 * 60 * 60 * 12 )) .sign(Algorithm.HMAC256(KEY)); } public static Map<String, Object> parseToken (String token) { return JWT.require(Algorithm.HMAC256(KEY)) .build() .verify(token) .getClaim("claims" ) .asMap(); } }
创建一个类用来接受user数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 package com.dreamxiao.newbackend.pojo;import com.fasterxml.jackson.annotation.JsonIgnore;import java.time.LocalDateTime;public class User { private Integer id; private String username; @JsonIgnore private String password; private String nickname; private String email; private String userPic; private LocalDateTime createTime; private LocalDateTime updateTime; public User () { } public User (Integer id, String username, String password, String nickname, String email, String userPic, LocalDateTime createTime, LocalDateTime updateTime) { this .id = id; this .username = username; this .password = password; this .nickname = nickname; this .email = email; this .userPic = userPic; this .createTime = createTime; this .updateTime = updateTime; } public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getPassword () { return password; } public void setPassword (String password) { this .password = password; } public String getNickname () { return nickname; } public void setNickname (String nickname) { this .nickname = nickname; } public String getEmail () { return email; } public void setEmail (String email) { this .email = email; } public String getUserPic () { return userPic; } public void setUserPic (String userPic) { this .userPic = userPic; } public LocalDateTime getCreateTime () { return createTime; } public void setCreateTime (LocalDateTime createTime) { this .createTime = createTime; } public LocalDateTime getUpdateTime () { return updateTime; } public void setUpdateTime (LocalDateTime updateTime) { this .updateTime = updateTime; } public String toString () { return "User{id = " + id + ", username = " + username + ", password = " + password + ", nickname = " + nickname + ", email = " + email + ", userPic = " + userPic + ", createTime = " + createTime + ", updateTime = " + updateTime + "}" ; } }
编写接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private static final Logger logger = LoggerFactory.getLogger(UserController.class); @PostMapping("/login") public Result login (String username, String password) { User u = userService.FindByUsername(username); if (u == null ) { return Result.error("用户名不存在" ); } else { if (u.getPassword().equals(StringTools.encodeByMD5(password))) { Map<String, Object> clains = new HashMap <>(); clains.put("id" , u.getId()); clains.put("username" , u.getUsername()); logger.info("生成jwt令牌" ); String token = JwtUtil.genToken(clains); return Result.success(token); } return Result.error("用户名或密码错误" ); } } }
1 2 User FindByUsername (String username) ;
1 2 3 4 5 6 @Override public User FindByUsername (String username) { return userMapper.FindByUsername(username); }
1 2 3 @Select("select * from user where username = #{username}") User FindByUsername (String username) ;
2.4获取登陆信息 1 2 3 4 5 6 7 8 9 10 11 12 @GetMapping("/userInfo") public Result<User> userInfo (@RequestHeader(name = "Authorization") String token) { Map<String, Object> stringObjectMap = JwtUtil.parseToken(token); String username=(String) stringObjectMap.get("username" ); User user = userService.FindByUsername(username); return Result.success(user); }
2.5更新用户信息 1 2 3 4 5 6 7 @PutMapping("/update") public Result update (@RequestBody User user) { userservice.update(user); return Result.success(); }
1 2 3 4 5 @Override public void update (User user) { user.setUpdateTime(LocalDateTime.now()); userMapper.update(user); }
1 2 3 4 @Update("update user set user.nickname=#{nickname},user.email=#{email}," + "user.update_time=#{updateTime} where user.id=#{id}") void update (User user) ;
2.6修改密码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @PatchMapping("/updatePwd") public Result updatePwd (@RequestBody Map<String, String> params, @RequestHeader("Authorization") String token) { String oldpwd = params.get("old_pwd" ); String newpwd = params.get("new_pwd" ); String repwd = params.get("re_pwd" ); if (!StringUtils.hasLength(oldpwd) || !StringUtils.hasLength(newpwd) || !StringUtils.hasLength(repwd)) { return Result.error("缺少必要参数" ); } Map<String, Object> stringObjectMap = JwtUtil.parseToken(token); String username = (String) stringObjectMap.get("username" ); Integer id = (Integer) stringObjectMap.get("id" ); User u = userService.FindByUsername(username); if (!Objects.equals(StringTools.encodeByMD5(oldpwd), u.getPassword())) { return Result.error("原密码填写不正确" ); } if (!newpwd.equals(repwd)) { return Result.error("两次填写的密码不一致" ); } userService.updatePwd(newpwd,id); return Result.success(); }
1 void updatePwd (String newpwd,Integer id) ;
1 2 3 4 5 @Override public void updatePwd (String newpwd, Integer id) { userMapper.updatePwd(StringTools.encodeByMD5(newpwd), id); }
1 2 @Update("update user set user.password=#{s},user.update_time=now() where id=#{id}") void updatePwd (String s, Integer id) ;