SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计)
- 🚀 注重版權(quán),轉(zhuǎn)載請(qǐng)注明原作者和原文鏈接
- 🥭 作者:Yuan-Programmer
- 🍎 主頁(yè):https://blog.csdn.net/weixin_47971206/article/details/121368075?spm=1001.2014.3001.5502
- 🍉 進(jìn)來(lái)的小伙伴點(diǎn)點(diǎn)贊呀
本案例第二篇教程地址:SpringBoot+Vue實(shí)現(xiàn)簡(jiǎn)單用戶管理平臺(tái)第二篇(前端設(shè)計(jì),接口對(duì)接)
demo地址預(yù)覽(域名正在審核,將就ip訪問(wèn)):http://43.138.223.178/user-manager
花了幾個(gè)小時(shí)做了一個(gè)SpringBoot+Vue的簡(jiǎn)單用戶管理demo項(xiàng)目,適合新手教程,項(xiàng)目已在Gitee上開(kāi)源,Gitee開(kāi)源地址:https://gitee.com/yuandewei/Yuan-SpringBoot/tree/master
Gitee上開(kāi)源的代碼跟本次的案例的代碼有些區(qū)別,本次案例稍微改了一點(diǎn)點(diǎn),不過(guò)不影響Gitee上的項(xiàng)目運(yùn)行,大致效果如下,功能可以訪問(wèn)demo地址測(cè)試哦
前言
開(kāi)發(fā)環(huán)境
開(kāi)發(fā)工具就不多介紹啦,就IDEA做后端,VSCode做前端,用其他的也都可以
技術(shù)
本次后端用到的技術(shù)呢: 主要就兩個(gè),SpringBoot + MyBatisPlus
前端的技術(shù)用到的技術(shù): Vue,結(jié)合腳手架以及element ui框架開(kāi)發(fā)前端
表設(shè)計(jì)
既然是用戶管理嘛,肯定有用戶表,我們先來(lái)設(shè)計(jì)表結(jié)構(gòu)
這里說(shuō)明一點(diǎn),這次案例是新手教程,著重講解功能的實(shí)現(xiàn),所以用戶信息參數(shù)方面就沒(méi)有那么嚴(yán)格的校驗(yàn),一般像號(hào)碼這種字段肯定是設(shè)置為 char(11) 并且后端要校驗(yàn)的
創(chuàng)建Maven工程
創(chuàng)建一個(gè)空的Maven項(xiàng)目,大家應(yīng)該都會(huì)了吧,還不會(huì)的小伙伴看之前的其他項(xiàng)目教程哦(我個(gè)人習(xí)慣創(chuàng)建maven工程,你喜歡直接創(chuàng)建springboot項(xiàng)目也可以,)
我這里創(chuàng)建好了一個(gè) user-manager的maven項(xiàng)目,創(chuàng)建好項(xiàng)目,點(diǎn)擊右下角選擇自動(dòng)導(dǎo)入,沒(méi)有彈出來(lái)也沒(méi)關(guān)系
引入依賴
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version><relativePath/></parent><properties><java.version>1.8</java.version></properties><dependencies><!-- MyBatis-Plus依賴 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.0</version></dependency><!-- 數(shù)據(jù)庫(kù)驅(qū)動(dòng) --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Web啟動(dòng)依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- SpringBoot測(cè)試依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 處理JSON的 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency></dependencies>基本配置
創(chuàng)建 com.xiaoyuan.usermanager 目錄,新建一個(gè)啟動(dòng)類 UserManagerApplication
在 resources 資源目錄下新建 application.yml 配置文件
圖片有誤,少了時(shí)間格式轉(zhuǎn)換三行代碼,看下面
server:# 端口port: 8081spring:# 數(shù)據(jù)源配置datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql:///l_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8username: xiaoyuanpassword: root# 時(shí)間格式轉(zhuǎn)換jackson:time-zone: GMT+8date-format: yyyy-MM-dd HH:mm:ssmybatis-plus:# mapper文件映射路徑mapper-locations: classpath*:mapper/*.xmlconfiguration:# 打印SQL語(yǔ)句log-impl: org.apache.ibatis.logging.stdout.StdOutImpldb層
entity實(shí)體類
新建 db 包,在 db 包下新建 entity 和 mapper 兩個(gè)包,在 entity 包下新建一個(gè) User 類
注意一下,圖片里 describe 有個(gè)注解忘記加上了,以下面代碼為準(zhǔn)
@Data public class User {// 主鍵ID@TableId(value = "id", type = IdType.AUTO)private Integer id;// 用戶名private String username;// 昵稱private String nickname;// 密碼private String password;// 號(hào)碼private String phone;// 性別private Character sex;// 描述@TableField(value = "`describe`") // describe屬于數(shù)據(jù)庫(kù)關(guān)鍵字,加上``區(qū)分private String describe;// 創(chuàng)建時(shí)間@TableField(fill = FieldFill.INSERT) // insert操作時(shí)自動(dòng)注入時(shí)間private Date gmtCreate; }mapper數(shù)據(jù)訪問(wèn)層
在 mapper 包下新建一個(gè) UserMapper,繼承MyBatisPlus的 BaseMapper 類,作為DAO層操作數(shù)據(jù)
MyBaitsPlus配置
這里創(chuàng)建的兩個(gè)包都與db包同級(jí)目錄
config配置類
創(chuàng)建一個(gè)config包,新建一個(gè)MyBatisPlusConfig 類
@Configuration public class MyBatisPlusConfig {/* 分頁(yè)插件 */@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 開(kāi)啟interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;} }handler處理
新建一個(gè) handler 包,包下新建一個(gè) MyMetaObjectHandler 類,實(shí)現(xiàn) MetaObjectHandler 類,改類有兩個(gè)方法,一個(gè)insert…在向數(shù)據(jù)庫(kù)插入數(shù)據(jù)的時(shí)候,會(huì)自動(dòng)插入我們?cè)O(shè)置的值
@Component public class MyMetaObjectHandler implements MetaObjectHandler {/*** 新增數(shù)據(jù)執(zhí)行* * insert插入數(shù)據(jù)到數(shù)據(jù)庫(kù)操作時(shí)執(zhí)行*/@Overridepublic void insertFill(MetaObject metaObject) {// 配置初始創(chuàng)建時(shí)間this.setFieldValByName("gmtCreate", new Date(), metaObject);}/*** 修改數(shù)據(jù)執(zhí)行* * update修改數(shù)據(jù)庫(kù)數(shù)據(jù)操作時(shí)執(zhí)行*/@Overridepublic void updateFill(MetaObject metaObject) {} }這里的 this.setFi… 第一個(gè)參數(shù)對(duì)應(yīng)的是User實(shí)體類的名字,不是表中的字段名,第二個(gè)參數(shù)的默認(rèn)值
Vo對(duì)象
新建一個(gè) vo 包,用于和前端交互數(shù)據(jù)的類
統(tǒng)一結(jié)果返回類
vo 包下新建一個(gè) R 類,作為我們統(tǒng)一返回給前端數(shù)據(jù)的類,
@Data public class R {private Boolean success;private Integer code;private String message;private Map<String, Object> data = new HashMap<>();// 把構(gòu)造方法私有化private R() {}// 成功靜態(tài)方法public static R ok() {R r = new R();r.setSuccess(true);r.setCode(200);r.setMessage("成功");return r;}// 失敗靜態(tài)方法public static R error() {R r = new R();r.setSuccess(false);r.setCode(201);r.setMessage("失敗");return r;}public R success(Boolean success){this.setSuccess(success);return this;}public R message(String message){this.setMessage(message);return this;}public R code(Integer code){this.setCode(code);return this;}public R data(String key, Object value){this.data.put(key, value);return this;} }vo 包下新建 QueryParam 類
@Data public class QueryParam {// 用戶名private String username;// 昵稱private String nickname;// 號(hào)碼private String phone;// 性別private String sex;// 創(chuàng)建時(shí)間private String time; }這里講一下吧,這個(gè)類是用來(lái)干嘛的呢?我們?cè)谛Ч故镜臅r(shí)候,是不是在上面看到有5個(gè)篩選條件,這5個(gè)篩選條件參數(shù)剛好對(duì)應(yīng)類中的5個(gè)屬性,我們統(tǒng)一封裝起來(lái)
service業(yè)務(wù)層
新建一個(gè) service 包,包下新建一個(gè) UserService 接口類,繼承MyBatisPlus的 IService 類
service 包下新建 impl 包,新建一個(gè) UserServiceImpl 實(shí)現(xiàn)類,繼承MyBatisPlus的 ServiceImpl 類,實(shí)現(xiàn)我們自己的 UserService 類
我們先在 UserService 接口類定義五個(gè)方法,接下來(lái)我們一一實(shí)現(xiàn)這五個(gè)功能
添加用戶
UserServiceImpl 實(shí)現(xiàn)類里實(shí)現(xiàn)添加用戶方法,這里只做了簡(jiǎn)單的非空判斷,其他參數(shù)的非法性校驗(yàn)可以自己額外完善
@Override public R insertUser(User user) {if (user == null) return R.error().message("參數(shù)錯(cuò)誤");// 用戶名String username = user.getUsername();// 構(gòu)建條件對(duì)象, 查詢是否已經(jīng)存在用戶名QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.select("id");wrapper.eq("username", username);wrapper.last("limit 1");// 查詢判斷, 如果查詢出來(lái)有數(shù)據(jù), 則不為nullif (this.baseMapper.selectOne(wrapper) != null) R.error().message("該用戶名已存在");// 執(zhí)行插入數(shù)據(jù)操作return this.baseMapper.insert(user) == 0 ? R.error().message("添加用戶失敗") : R.ok(); }刪除用戶
刪除用戶就比較簡(jiǎn)單啦,肯定有人會(huì)問(wèn),前端做了非空校驗(yàn),后端怎么還要做參數(shù)校驗(yàn)校驗(yàn)?zāi)?#xff1f;
其實(shí)前后端都做是最好的,有繞過(guò)前端發(fā)送請(qǐng)求的,就比如我們自己測(cè)試接口時(shí)用的postman, apifox,后端多做一層校驗(yàn),避免直接操作數(shù)據(jù)庫(kù),我這里也是比較簡(jiǎn)單的做了校驗(yàn)
@Override public R deleteUser(Integer id) {if (id == null || id <= 0) return R.error().message("參數(shù)錯(cuò)誤");return this.baseMapper.deleteById(id) == 0 ? R.error().message("刪除失敗") : R.ok(); }一鍵刪除多個(gè)用戶
刪除多個(gè)用戶也沒(méi)難度,將多個(gè)用戶的編號(hào)放到一個(gè)集合中,一次刪除多個(gè)
@Override public R deleteUserMore(List<Integer> ids) {if (ids.size() == 0) return R.error().message("參數(shù)錯(cuò)誤");return this.baseMapper.deleteBatchIds(ids) != ids.size() ? R.error().message("刪除失敗") : R.ok(); }編輯用戶
這個(gè)也沒(méi)什么難度,做個(gè)簡(jiǎn)單校驗(yàn),然后根據(jù)ID更新用戶信息(參數(shù)其他合法性校驗(yàn)可以自己額外做哦)
@Overridepublic R modifyUser(User user) {if (user == null || user.getId() == null || user.getId() <= 0) return R.error().message("參數(shù)錯(cuò)誤");return this.baseMapper.updateById(user) == 0 ? R.error().message("編輯用戶失敗") : R.ok();}獲取單個(gè)用戶信息
先實(shí)現(xiàn)這個(gè)吧,這個(gè)也很簡(jiǎn)單,直接通過(guò)用戶編號(hào)查詢用戶的信息返回即可
@Override public R getUserInfoById(Integer id) {if (id == null || id <= 0) return R.error().message("參數(shù)錯(cuò)誤");return R.ok().data("userInfo", this.baseMapper.selectById(id)); }查詢用戶列表
先創(chuàng)建編寫(xiě)SQL語(yǔ)句的文件,在 resources 下新建 mapper 包,包下新建 UserMapper.xml 文件
代碼中的SQL語(yǔ)句不能包含注釋,所以我在圖片給出了每行的注釋,代碼中刪掉了,對(duì)應(yīng)看著
我們大致來(lái)分析一下上面的SQL語(yǔ)句,首先 select * from user這里沒(méi)毛病吧,咋們是管理用戶,所有信息都得要上,* 查詢所有
后面 where 里有個(gè) 1 = 1 作用是恒等式,為了防止沒(méi)有做篩選條件時(shí),queryParam 條件對(duì)象為 null 導(dǎo)致 where 里面沒(méi)東西,執(zhí)行SQL語(yǔ)句的時(shí)候就會(huì)出現(xiàn) where 后面沒(méi)加?xùn)|西,就會(huì)拋出異常
CONCAT 函數(shù)的作用是拼接,當(dāng)然你直接用下面這樣也行,推薦還是使用CONCAT,以后會(huì)遇到的,還有就是 % 只寫(xiě)右邊就可以了,避免全表掃描,采用單模糊查詢
and nickname like #{queryParam.nickname} '%'DATE_FORMAT 函數(shù)作用是對(duì)時(shí)間進(jìn)行格式化,2022-05-06 11:17:36 轉(zhuǎn)換為 2022-05-06
SQL語(yǔ)句寫(xiě)好了,更新一下我們的 UserMapper 類,映射到 UserMapper.xml 文件的SQL語(yǔ)句,函數(shù)名就是 < select id=“xxxx”> 這里id的值
@Repository public interface UserMapper extends BaseMapper<User> {/*** 查詢用戶列表* @param page 分頁(yè)對(duì)象* @param queryParam 篩選條件* @return*/IPage<User> findUserList(Page<User> page, QueryParam queryParam); }最后就是在 UserServiceImpl 實(shí)現(xiàn)查詢用戶列表的方法
@Override public R findUserList(Integer index, Integer size, QueryParam queryParam) {if (index == null || size == null || index <= 0 || size <= 0) {return R.error().message("參數(shù)錯(cuò)誤");}else if (size > 10) {return R.error().message("一次最多10條數(shù)據(jù)");}// 構(gòu)建分頁(yè)對(duì)象Page<User> page = new Page<>(index, size);// 查詢IPage<User> iPage = this.baseMapper.findUserList(page, queryParam);// 回傳兩個(gè)數(shù)據(jù), 一個(gè) userList --> 用戶數(shù)據(jù)列表, 一個(gè) total -> 總頁(yè)數(shù)return R.ok().data("userList", iPage.getRecords()).data("total", iPage.getTotal()); }controller控制層
這里是最后一步了,處理接口,我們采用 RESTful 的風(fēng)格,相同的路徑處理不用的操作
接口測(cè)試
最后,在啟動(dòng)類加上兩個(gè)注解,一個(gè) MapperScan 掃描我們的 mapper 類,一個(gè) ComponentScan 掃描我們的組件
@SpringBootApplication @MapperScan(basePackages = {"com.xiaoyuan.usermanager.db.mapper"}) @ComponentScan({"com.xiaoyuan"}) public class UserManagerApplication {public static void main(String[] args) {SpringApplication.run(UserManagerApplication.class, args);} }OK,到這里功能已經(jīng)全部做好了,我們測(cè)試一下接口,運(yùn)行啟動(dòng)類,我這里只展示部分接口的測(cè)試接口,全部接口我已經(jīng)測(cè)試過(guò),都沒(méi)有問(wèn)題了
大家可以自己去測(cè)試每個(gè)接口,我用的時(shí) ApiFox 工具,非常好用,還能一鍵導(dǎo)出接口文檔,可以顯示接口耗時(shí),分組分項(xiàng)目分接口分環(huán)境,非常的方便
添加用戶,成功插入數(shù)據(jù)
當(dāng)然,你可以在代碼里面用測(cè)試,新建一個(gè) SpringBoot 的測(cè)試類,測(cè)試業(yè)務(wù)層也可以的,如下
其他的就不一一放出來(lái)了,大伙自己去試試吧~
擴(kuò)展(攔截器,權(quán)限攔截)
像管理這種一般都會(huì)有權(quán)限的,總不可能每個(gè)人都能訪問(wèn)自己的接口來(lái)增刪改查用戶吧?如何做到不給其他人訪問(wèn)自己的接口,判斷別人是否有權(quán)限訪問(wèn)呢?
下面我們簡(jiǎn)單來(lái)設(shè)計(jì)一下,理解大概過(guò)程
首先,usermanager 主目錄下創(chuàng)建兩個(gè)包,一個(gè) interceptor 攔截器,一個(gè) WebMVCConfig MVC的配置類
interceptor 包下新建一個(gè) PermissionInterceptor 類,實(shí)現(xiàn) HandlerInterceptor 類
攔截器有三個(gè)階段,preHandle -> postHandle -> afterCompletion,依次按順序執(zhí)行,只有前一個(gè)return返回true,才會(huì)執(zhí)行下一個(gè)階段方法,簡(jiǎn)單介紹三個(gè)階段
- preHandle:controller執(zhí)行目標(biāo)方法之前執(zhí)行,一般用于權(quán)限驗(yàn)證等操作
- postHandle:controller執(zhí)行完目標(biāo)方法返回(如調(diào)用service業(yè)務(wù)層的方法),在前端數(shù)據(jù)渲染之前執(zhí)行,一般用于更改視圖數(shù)據(jù)
- afterCompletion:整個(gè)接口訪問(wèn)執(zhí)行完畢,前端數(shù)據(jù)渲染完成,執(zhí)行此方法,一般用于資源釋放等操作
很明顯,我們這個(gè)權(quán)限驗(yàn)證攔截就是在 preHandle 階段去全性
這個(gè) code 呢就是我們自己定義的權(quán)限碼,我這里只是隨便敲了長(zhǎng)長(zhǎng)的一段,反正自己知道就好,你可以做加密處理,這里我簡(jiǎn)單模擬一下
@Component public class PermissionInterceptor implements HandlerInterceptor {private static final String code = "dwagfhwhgiawpfwabifpjwaidjwaidwiafihwigfhwaigwhaipgwaihiwahifhwdefef";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 放行OPTIONS請(qǐng)求if (HttpMethod.OPTIONS.matches(request.getMethod())) {return true;}// 獲取請(qǐng)求頭里面的 Authentication 屬性值String authentication = request.getHeader("Authentication");// 兩者相等 -> 通過(guò)放行, 兩者不相等 -> 不通過(guò)不放行if (code.equals(authentication)) {// 放行return true;}else {// 不放行, 回傳沒(méi)有權(quán)限response.setContentType("text/html;charset=utf-8");response.getWriter().println(JSON.toJSONString(R.error().message("沒(méi)有操作權(quán)限")));return false;}} }config 包下新建一個(gè) WebMVCConfig 類,實(shí)現(xiàn) WebMvcConfigurer 類,設(shè)置攔截器
@Configuration public class WebMVCConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new PermissionInterceptor()) // 添加攔截器.addPathPatterns("/user/**"); // 選擇攔截路徑,攔截/user下的所有請(qǐng)求} }好的,我們接下來(lái)看看效果,當(dāng)然,就不適合在代碼用SpringBoot測(cè)試類啦,因?yàn)樾r?yàn)請(qǐng)求頭
我們采用接口測(cè)試工具,老樣子,我使用的是ApiFox,你可以使用postman等其他工具
首先我們繼續(xù)運(yùn)行一下之前寫(xiě)好的請(qǐng)求路徑(沒(méi)加Authentication 權(quán)限碼),可以看到,我們?cè)L問(wèn)的是查詢用戶列表接口,顯示沒(méi)有權(quán)限
接下來(lái)我們?cè)?header 請(qǐng)求頭加上我們的 Authentication 的權(quán)限碼,同樣的路徑,測(cè)試一下
是不是就成功訪問(wèn)到了
我們隨便改錯(cuò)一個(gè)字母,也成功顯示沒(méi)有權(quán)限,除非你的權(quán)限碼被別人知道了,或者被破解了(設(shè)置的復(fù)雜一點(diǎn)再加密基本不可能被破),不然你的接口別人訪問(wèn)不了
🌹 結(jié)束語(yǔ)
好了,整篇的教程呢到這也就結(jié)束,整篇教程即為原創(chuàng)一字一字手敲,也花了心思想怎么寫(xiě)怎么設(shè)計(jì)才能更好的直觀簡(jiǎn)潔展示給大家,讓大家能看懂
最后,關(guān)于教程還有什么不懂的可以評(píng)論區(qū)留言,我一定會(huì)回復(fù)的,或者有什么更好的建議和想法也可以在評(píng)論區(qū)留言,看到好的我會(huì)一一采納,感謝大家的支持
再一次附上Gitee開(kāi)源地址:https://gitee.com/yuandewei/Yuan-SpringBoot/tree/master 不用大伙翻上去復(fù)制了
- 都看到這里啦,點(diǎn)點(diǎn)贊呀 😋
- 感謝閱讀 😘
總結(jié)
以上是生活随笔為你收集整理的SpringBoot+Vue实现简单用户管理平台第一篇(后端接口设计)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: intellij idea cpu占用率
- 下一篇: html5倒计时秒杀怎么做,vue 设