快速上手SpringBoot專案(登入註冊保姆級教程)
文章首發於:MakerHu的個人部落格(makerhu.top)
未經允許請勿轉載!
前置條件
使用本教程的前置條件是開發環境中已安裝了以下幾個東西,若無可以先找相關教程安裝配置好。
管理工具:maven
IDE: IDEA
資料庫: MySQL
測試工具:Postman(非必須,但方便測試且安裝和使用都挺簡單的)
建立專案
注意:建立專案時保持網路通暢
-
開啟IDEA
-
新建專案
情況一:
情況二:
設定專案的基本資訊,其中注意jdk版本要與Java版本匹配,這裡使用jdk1.8和java8
選擇SpringBoot版本,選擇專案依賴(依賴可以建立完專案後在pom檔案中修改)
至此專案就建立完成啦!
目錄結構(初始狀態)
配置資料庫
建立完專案後,如果直接執行專案,我們會發現專案報錯了
報錯的原因是我們在建立專案時匯入了資料庫相關的依賴,但是專案卻還沒有進行資料庫相關配置
所以接下來我們先進行資料庫的配置
建立資料庫
要配置資料庫,首先咱們得有個資料庫,因此我們先用MySQL建立一個。由於本專案要演示登入註冊功能的實現,所以在此我將建立一個使用者表,儲存使用者的賬號資訊。
- 按Win+R開啟“執行”,輸入cmd
-
輸入
mysql -u root -p
後輸入密碼,登入MySQL -
建立資料庫
create database logindemo
logindemo -
進入資料庫
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包為父子關係,也可以並列,這取決於你的喜好
最終效果見下一步
-
最終目錄結構
包含
domain
repository
service
serviceImpl
controller
utils
config
這時候眼尖的同學就發現了,怎麼還多了倆:
utils
config
這兩個包的作用:
- **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)