文章首發於:MakerHu的個人博客(www.makerhu.com)
未經允許請勿轉載!
前置條件
使用本教程的前置條件是開發環境中已安裝了以下幾個東西,若無可以先找相關教程安裝配置好。
管理工具:maven
IDE: IDEA
數據庫: MySQL
測試工具:Postman(非必須,但方便測試且安裝和使用都挺簡單的)
創建項目
注意:創建項目時保持網絡通暢
-
打開IDEA

-
新建項目
情況一:

情況二:

設置項目的基本信息,其中注意jdk版本要與Java版本匹配,這里使用jdk1.8和java8

選擇SpringBoot版本,選擇項目依賴(依賴可以創建完項目后在pom文件中修改)


至此項目就創建完成啦!
目錄結構(初始狀態)

配置數據庫
創建完項目后,如果直接運行項目,我們會發現項目報錯了

報錯的原因是我們在創建項目時導入了數據庫相關的依賴,但是項目卻還沒有進行數據庫相關配置
所以接下來我們先進行數據庫的配置
創建數據庫
要配置數據庫,首先咱們得有個數據庫,因此我們先用MySQL創建一個。由於本項目要演示登錄注冊功能的實現,所以在此我將創建一個用戶表,保存用戶的賬號信息。
- 按Win+R打開“運行”,輸入cmd

-
輸入
mysql -u root -p后輸入密碼,登錄MySQL
-
創建數據庫
create database logindemologindemo為數據庫名,根據你的情況修改
-
進入數據庫
use logindemo
-
創建user表
CREATE TABLE user ( uid int(10) primary key NOT NULL AUTO_INCREMENT, uname varchar(30) NOT NULL, password varchar(255) NOT NULL, UNIQUE (uname) );
uid: 用戶編號,主鍵,自增
uname: 用戶名,作為登錄的賬號(業務主鍵),不可重復
password: 密碼,因為可能要加密,所以長度設了較長的255
-
查看表是否創建成功
desc user;
到這數據庫就創建完成啦,接下來就是在項目中配置數據庫相關信息了。
配置數據庫
-
找到配置文件application.properties

-
輸入數據庫相關配置信息(此處配置了項目端口號為8081,可不配置,默認端口號為8080)
注意:配置url處logindemo改為你的數據庫名稱
# 配置端口號為8081 server.port=8081 # 配置數據庫 # 配置驅動 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 若連接的是雲數據庫則將localhost改為雲端ip spring.datasource.url=jdbc:mysql://localhost:3306/logindemo?serverTimezone=UTC # Mysql用戶 spring.datasource.username=root # Mysql對應用戶密碼 spring.datasource.password=123456
現在再次運行項目就能成功運行啦!
-
在IDEA中連接數據庫(此步非必須,只是為了開發方便)
在IDEA中連接數據庫可以讓我們在開發時直接可視化查看數據庫的詳細信息,建議配置一下。

配置數據庫基本信息
注意:這一步有可能出現時區錯誤或者缺少依賴文件!!!
解決方案
時區錯誤:見圖中配置時區
缺少文件:根據提示點擊下載,但由於服務器在外網,有可能需要合理地上網


完成以上配置后就能在IDEA中管理數據庫啦!

項目架構圖
在說項目的目錄結構之前,我們先來聊一聊后端的架構大概是什么樣的,方便我們對目錄結構的理解。

- 數據持久層是的目的是在java對象與數據庫之間建立映射,也就是說它的作用是將某一個Java類對應到數據庫中的一張表。在我們的項目中,就將創建一個實體類User映射到數據庫的user表,表中的每個字段對應於實體類的每個屬性。而之前配置的JPA的作用就是幫助我們完成類到數據表的映射。
- repository: 存放一些數據訪問類(也就是一些能操縱數據庫的類)的包,比如存放能對user表進行增刪改查的類
- domain:存放實體類的包,比如User類,其作為對應數據庫user表的一個實體類
- 業務邏輯層的作用是處理業務邏輯。比如在本項目中,我們就在業務邏輯層實現登錄注冊的邏輯,像是判斷是否有用戶名重復,密碼是否正確等邏輯
- service: 存放業務邏輯接口的包
- serviceImpl: 存放業務邏輯實現類的包,其中的類實現service中的接口
- 控制層的作用是接收視圖層的請求並調用業務邏輯層的方法。比如視圖層請求登錄並發來了用戶的賬號和密碼,那么控制層就調用業務邏輯層的登錄方法,並將賬號密碼作為參數傳入,在將結果返回給視圖層。
- controller: 存放控制器的包。比如UserController
- 視圖層的作用是展現數據,由於本項目寫的是純后端,就不展開解釋視圖層了。
注意:根據架構我們可以發現,最佳的開發方式是自底向上開發,因為包之間的調用是上層調用下層,所以下層現實現能保證實現多少測試多少
完善項目的基本目錄結構
根據上述架構圖的設計,我們就能創建對應的包讓我們的項目框架更加清晰了。
-
創建各種包(以domain包為例)
注意本項目中service與serviceImpl包為父子關系,也可以並列,這取決於你的喜好
最終效果見下一步


-
最終目錄結構
包含
domainrepositoryserviceserviceImplcontrollerutilsconfig
這時候眼尖的同學就發現了,怎么還多了倆:
utilsconfig這兩個包的作用:
- **utils: **存放工具類,一些自己封裝的工具
- **config: **存放配置類,一些配置如登錄攔截器,安全配置等
這里先建好了再說,具體怎么用之后會說。
登錄注冊功能實現
根據框架特點,我們將自底向上開發,所以將按照 實體類-dao-service-serviceImpl-controller 的順序逐步開發。
所有類或接口的目錄位置
為了方便你在下面的教程中明確的知道文件應該創建在什么位置,在此我就先把所有文件的目錄位置展示出來了,你可以在需要的時候隨時回來查看,現在可以先跳過這一步。

實現User實體類
-
在domain中創建User.java


-
創建對應user表中字段的屬性
其中注意要添加
@Table(name = "user")和@Entity注解- @Table(name = "user") 說明此實體類對應於數據庫的user表
- @Entity 說明此類是個實體類
主鍵uid上要加上
@Id與@GeneratedValue(strategy = GenerationType.IDENTITY)注解//domain中的User.java package com.springboot.springbootlogindemo.domain; import javax.persistence.*; @Table(name = "user") @Entity public class User { // 注意屬性名要與數據表中的字段名一致 // 主鍵自增int(10)對應long @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long uid; // 用戶名屬性varchar對應String private String uname; // 密碼屬性varchar對應String private String password; }
-
為屬性生成get,set方法
-
將光標移至要插入get, set方法的位置
-
右鍵-generate-getter and setter


-
選中所有屬性-OK

-
最后得到User.java(也可以純手敲)
package com.springboot.springbootlogindemo.domain; import javax.persistence.*; @Table(name = "user") @Entity public class User { // 注意屬性名要與數據表中的字段名一致 // 主鍵自增int(10)對應long @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long uid; // 用戶名屬性varchar對應String private String uname; // 密碼屬性varchar對應String private String password; public long getUid() { return uid; } public void setUid(long uid) { this.uid = uid; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }至此User實體類就創建好啦,如果要實現其他表的實體類也類似。
-
實現UserDao
-
在repository包中創建UserDao接口


-
添加一些訪問數據庫的方法(這里添加的是根據用戶名查詢用戶方法)
- 首先要添加注解
@Repository - 接口要繼承
JpaRepository,這樣JPA就能幫助我們完成對數據庫的映射,也就是說接口里寫的方法只要符合格式可以不需要實現SQL語句就能直接用了。 - 如果JPA沒有提供你想要的方法,可以自定義SQL語句

package com.springboot.springbootlogindemo.repository; import com.springboot.springbootlogindemo.domain.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface UserDao extends JpaRepository<User, Long> { User findByUname(String uname); //通過用戶名uname查找用戶,注意要按照JPA的格式使用駝峰命名法 User findByUnameAndPassword(String uname, String password);//通過用戶名uname和密碼查找用戶 }由於我們只實現登錄注冊功能,所以只要有根據賬號密碼查詢用戶和插入用戶信息的方法就行了,這里我們已經實現了根據用戶名密碼查找用戶的方法,而插入用戶信息的方法save(object o)JPA已經幫我們實現了,可以直接調用,這里就不需要寫了。
注意:這里接口方法的命名要按照JPA提供的命名格式,比如findBy, deleteBy等等,且要求駝峰命名法。如果自定義查詢方法可以不遵守這個規則
自定義查詢方法例子(本項目不需要用到):
@Query(value = "select * from user where uname LIKE ?1 OR email LIKE ?2 OR lastdid LIKE ?3 OR uid LIKE ?4",nativeQuery = true) Page<User> findUserswithoutgender( String uname, String email, String lastdid, String uid, Pageable request ); - 首先要添加注解
實現UserService
-
在service包中創建UserService接口


-
添加登錄注冊需要用到的業務邏輯方法
- 最終UserService的完整代碼
package com.springboot.springbootlogindemo.service; import com.springboot.springbootlogindemo.domain.User; public interface UserService { /** * 登錄業務邏輯 * @param uname 賬戶名 * @param password 密碼 * @return */ User loginService(String uname, String password); /** * 注冊業務邏輯 * @param user 要注冊的User對象,屬性中主鍵uid要為空,若uid不為空可能會覆蓋已存在的user * @return */ User registService(User user); } -
完成了接口方法的定義,接下來是在UserServiceImpl中實現這些方法啦
實現UserServiceImpl
我們將在UserServiceImpl中實現UserService中的方法,完整的UserServiceImpl代碼在此步驟的最后一小步里
-
在serviceImpl包中創建UserServiceImpl類


-
添加需要實現的方法
-
添加
implements UserService此時會報錯,但沒關系,只是因為方法還沒實現。

-
鼠標懸停在紅色波浪線自動生成需要實現的方法(也可以手動一個個寫)


-
生成方法后的樣子

-
-
實現登錄業務邏輯
-
因為要用到UserDao中的方法,所以先通過
@Resource注解幫助我們實例化UserDao對象 -
登錄業務邏輯代碼
@Resource private UserDao userDao; @Override public User loginService(String uname, String password) { // 如果賬號密碼都對則返回登錄的用戶對象,若有一個錯誤則返回null User user = userDao.findByUnameAndPassword(uname, password); // 重要信息置空 if(user != null){ user.setPassword(""); } return user; }
-
-
實現注冊業務邏輯
-
注冊業務邏輯代碼
@Override public User registService(User user) { //當新用戶的用戶名已存在時 if(userDao.findByUname(user.getUname())!=null){ // 無法注冊 return null; }else{ //返回創建好的用戶對象(帶uid) User newUser = userDao.save(user); if(newUser != null){ newUser.setPassword(""); } return newUser; } }
-
-
添加
@Service注解
-
最終UserServiceImpl完整代碼
package com.springboot.springbootlogindemo.service.serviceImpl; import com.springboot.springbootlogindemo.domain.User; import com.springboot.springbootlogindemo.repository.UserDao; import com.springboot.springbootlogindemo.service.UserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service public class UserServiceImpl implements UserService { @Resource private UserDao userDao; @Override public User loginService(String uname, String password) { // 如果賬號密碼都對則返回登錄的用戶對象,若有一個錯誤則返回null User user = userDao.findByUnameAndPassword(uname, password); // 重要信息置空 if(user != null){ user.setPassword(""); } return user; } @Override public User registService(User user) { //當新用戶的用戶名已存在時 if(userDao.findByUname(user.getUname())!=null){ // 無法注冊 return null; }else{ //返回創建好的用戶對象(帶uid) User newUser = userDao.save(user); if(newUser != null){ newUser.setPassword(""); } return newUser; } } } -
至此UserServiceImpl就寫完啦!
實現工具類Result
工具類Result的作用是作為返回給前端的統一后的對象。也就是說返回給前端的都是Result對象,只是對象中的屬性不太一樣,這樣方便前端固定接收格式。
-
在utils包中創建Result類


-
最終Result代碼
package com.springboot.springbootlogindemo.utils; public class Result<T> { private String code; private String msg; private T data; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public Result() { } public Result(T data) { this.data = data; } public static Result success() { Result result = new Result<>(); result.setCode("0"); result.setMsg("成功"); return result; } public static <T> Result<T> success(T data) { Result<T> result = new Result<>(data); result.setCode("0"); result.setMsg("成功"); return result; } public static <T> Result<T> success(T data,String msg) { Result<T> result = new Result<>(data); result.setCode("0"); result.setMsg(msg); return result; } public static Result error(String code, String msg) { Result result = new Result(); result.setCode(code); result.setMsg(msg); return result; } }可以看出Result是個模板類,因此想要返回什么數據類型給前端都行,如
Result<User>,要是沒看懂沒關系,看到下面就知道怎么用了。因為里面有很多靜態方法,可以直接用類名.方法名調用。
實現UserController
-
在controller包中創建UserController類


-
添加
@RestController與@RequestMapping("/user")注解,注入UserService- 注解@RequestMapping中的"/user"是這個控制器類的基路由

-
實現登錄的控制
這里的
@PostMapping("/login")表示處理post請求,路由為/user/login@PostMapping("/login") public Result<User> loginController(@RequestParam String uname, @RequestParam String password){ User user = userService.loginService(uname, password); if(user!=null){ return Result.success(user,"登錄成功!"); }else{ return Result.error("123","賬號或密碼錯誤!"); } } -
實現注冊的控制
這里的
@PostMapping("/register")表示處理post請求,路由為/user/register@PostMapping("/register") public Result<User> registController(@RequestBody User newUser){ User user = userService.registService(newUser); if(user!=null){ return Result.success(user,"注冊成功!"); }else{ return Result.error("456","用戶名已存在!"); } } -
完整的UserController代碼
package com.springboot.springbootlogindemo.controller; import com.springboot.springbootlogindemo.domain.User; import com.springboot.springbootlogindemo.service.UserService; import com.springboot.springbootlogindemo.utils.Result; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @RestController @RequestMapping("/user") public class UserController { @Resource private UserService userService; @PostMapping("/login") public Result<User> loginController(@RequestParam String uname, @RequestParam String password){ User user = userService.loginService(uname, password); if(user!=null){ return Result.success(user,"登錄成功!"); }else{ return Result.error("123","賬號或密碼錯誤!"); } } @PostMapping("/register") public Result<User> registController(@RequestBody User newUser){ User user = userService.registService(newUser); if(user!=null){ return Result.success(user,"注冊成功!"); }else{ return Result.error("456","用戶名已存在!"); } } }至此所有的代碼就都寫完啦!!!
接下來就是運行測試一下是否成功就行了。
Postman測試
-
打開postman

-
測試注冊用戶

輸入選則請求方式Post,輸入路由
http://localhost:8081/user/register,輸入用戶json對象后點擊Send{ "uname": "hhh", "password": "123" }成功收到后端返回消息

-
登錄測試

類似於注冊測試
- 請求方式:POST
- url:
http://localhost:8081/user/login - 參數:見圖中4,5步
至此整個項目都寫完並測試完啦!感謝你能耐心看到這,希望本教程對你有所幫助。
項目完整代碼
MakerHu/springboot-login-demo: Springboot后端登錄注冊項目演示demo (github.com)
