經典權限五張表案例分析

文章目錄

  • 模塊分析
    • 模塊
    • 分析
  • 描述五張表的關系
  • 重要知識講解
    • 抽取成一個BaseServlet
    • SpringIOC思想(底層)
      • 實現代碼
      • IOC概述
    • SPI機制(為學習框架做思想和技術鋪墊)
      • SPI引入
        • 1. 標準/規范
        • 2. 具體的實現
        • 3. 調用
      • SPI介紹
      • SPI練習JDBC4.0免注冊驅動原理
      • Servlet實現方式三 ServletContainerInitializer

模塊分析

模塊

項目分為三個模塊

  1. 用戶模塊:完成增刪改查
  2. 角色模塊:增刪改查
  3. 權限模塊:增刪改查

分析

用戶和角色的關系
一個用戶有多個角色,張三可以是SVIP,也可以是綠鉆
一個角色可以對應多個用戶,SVIP可以是張三,也可以是李四
結果:用戶和角色屬于多對多的關系,根據表設計原則,多對多關系創建中間表,在中間表起碼要有另外倆張主表用戶和角色的主鍵作為外鍵進行關聯
角色和權限的關系
一個角色有多個權限,SVIP可以點贊20次,可以使qq名變紅
一個權限可以對應多個角色,使qq名變紅可以是SVIP,也可以是VIP
結果:角色和權限屬于多對多的關系,根據表設計原則,多對多關系創建中間表,在中間表起碼有另外倆張主表權限和角色的主鍵作為外鍵進行關聯
:用戶 角色 權限具有經典的五張表

描述五張表的關系

image.png

重要知識講解

抽取成一個BaseServlet

問題:對用戶進行增刪改查,那么單對用戶就要寫4個Servlet,這樣創建的類太多比較麻煩
解決措施:我們想的是對于用戶只創建一個Servlet,路徑的話變成/user/*,這樣關于用戶的所有操作都會放到這個Servlet類中,在里面定義方法來分別操作用戶,方法名和路徑名保持相同,代碼看著簡單明了,很簡潔
問題:但是這樣做我們就只能使用在用戶模塊,不能使用其他模塊,造成代碼冗余,還得必須使用if判斷到底執行哪個方法
解決措施:前面已經學過可以獲取前端的請求數據,那么就可以獲取到請求路徑,然后用反射來執行方法,然后將其抽取到一個類中,讓其他模塊創建的Servlet類繼承這個類,其他模塊的Servlet類中只寫操作方法即可
關鍵:this關鍵字
代碼如下

public class BaseServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//獲取請求路徑String uri = request.getRequestURI();int i = uri.lastIndexOf("/");String methodName = uri.substring(i + 1);//判斷方法名//名字固定,不利于整體書寫
//        if ("findAll".equals(methodName)){
//            findAll(request,response);
//        } else if ("update".equals(methodName)) {
//            update(request,response);
//        } else if ("add".equals(methodName)) {
//            add(request,response);
//        }else if ("delete".equals(methodName)){
//            delete(request,response);
//        }//用反射技術,使用固定代碼執行所有方法//方法名和路徑相同,利用反射獲取方法名Class aClass = this.getClass();try {Method method = aClass.getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);method.invoke(this,request,response);} catch (Exception e) {throw new RuntimeException(e);}}
}
@WebServlet("/user/*")
public class UserServlet extends BaseServlet {private void delete(HttpServletRequest request, HttpServletResponse response) {System.out.println("刪除用戶");}public void add(HttpServletRequest request, HttpServletResponse response) {System.out.println("增加用戶");}public void update(HttpServletRequest request, HttpServletResponse response) {System.out.println("更新用戶");}public void findAll(HttpServletRequest request, HttpServletResponse response) {}
}

SpringIOC思想(底層)

實現代碼

問題:我們以前創建對象都是通過new創建對象,例如:創建業務層對象:
UserServiceImple userServiceImpl = new UserServiceImpl();
這種方式創建對象的弊端是:嚴重耦合。如果業務層實現類UserServiceImpl被刪除了,web會報錯。或者在實際開發中向對業務層進行擴展,一般是定義一個新的業務層類UserServiceImpl2,然后將之前的UserServiceImpl替換,就造成web層無法運行,那么太過于耦合
解決措施:降低耦合。就是不在web層中使用new方式創建對象
使用:反射+面向接口編程+讀取配置文件+工程設計模式等方式來取代new創建對象

  1. 定義接口

在業務層下定義接口,然后定義一個impl包,將UserServiceImpl類放到impl包下,這樣就可以將上面創建業務層對象改成:
UserService userService = new UserServiceImpl();
這樣的話就是實現左邊解耦了,如果擴展實現類只需要修改等號右邊

  1. 書寫properties文件

在resources下定義一個beans.properties文件,然后按照key=value格式書寫,key:userService,value:寫UserServiceImpl的全路徑名

  1. 使用反射+讀取配置文件創建對象

使用ResourceBundle抽象類去讀取properties配置文件,利用反射創建對象

  1. 定義一個工具類,使用工廠設計模式來創建對象

定義一個Map集合,key存properties文件內容=左邊的值,value存用反射創建的對象
代碼如下
工廠類

package com.itheima.case2.utils;import java.util.HashMap;
import java.util.ResourceBundle;/*TODO:當前工廠類的作用就是創建對象的回顧:一個類對象:1)單例 單個對象2)多例 多個對象我們這里實現產生的對象是單例 userService=com.itheima.case2.service.impl.UserServiceImpl1.創建一個Map集合: new HashMap<String,Object>();2.Map集合的key:例如配置文件等號左邊的標識userService roleService3.Map集合的value:就是創建的對象UserServiceImpl 類的對象  RoleServiceImpl類的對象4.實現步驟:1)創建map集合存儲創建的對象2)定義靜態方法創建具體類的對象3)在靜態方法中判斷map集合的key是否有值,如果沒有值,說明第一創建對象4)直接使用反射+讀取配置文件方式創建對象5)將創建的對象作為map集合的value和key存入到map中6)返回給調用者創建的對象*/
public class BeansFactory {// 1)創建map集合存儲創建的對象/*key            valueuserService    UserServiceImpl0x001roleService    RoleServiceImpl0x002*/private static HashMap<String,Object> map = new HashMap<>();// 2)定義靜態方法創建具體類的對象//多線程安全問題:t1 t2public static synchronized  <T> T getInstance(String key) throws Exception{//String key=userService roleService// 3)在靜態方法中判斷map集合的key是否有值,如果沒有值,說明第一創建對象Object obj = map.get(key);// 4)直接使用反射+讀取配置文件方式創建對象if(obj == null){//說明當前map集合中沒有傳遞的key對應的值//4.1使用反射+讀取配置文件創建對象ResourceBundle bundle = ResourceBundle.getBundle("beans");//參數beans表示要關聯的配置文件的名字,不能書寫后綴名//4.2根據配置文件的key獲取值 t1//userService=com.itheima.case2.service.impl.UserServiceImplString classNameStr = bundle.getString(key);//"com.itheima.case2.service.impl.UserServiceImpl"//4.3使用反射創建對象Class<?> clazz = Class.forName(classNameStr);obj = clazz.newInstance();//調用UserServiceImpl類的無參構造方法// 5)將創建的對象作為map集合的value和key存入到map中map.put(key,obj);//t1線程創建的對象0x001 t2線程創建的對象0x002}// 6)返回給調用者創建的對象return (T)obj;}}

配置文件

userService=com.itheima.case2.service.impl.UserServiceImpl

web層UserServlet

UserService userService = BeanFactory.getInstance("userService");

IOC概述

Inversion of Control:控制反轉
以前我們要獲取對象,我們自己new主動獲取,現在有了工廠模式,我們需要獲取對象,是工廠創建,我們被動接收工廠創建的對象,這就是控制反轉,說白了就是ioc采用工廠模式創建對象達到解耦合
其實SpringIOC底層是Map集合,我們經常會說SpringIOC容器即Map集合。

SPI機制(為學習框架做思想和技術鋪墊)

SPI引入

1. 標準/規范
  1. 工程 spi_interface
  2. 只有一個接口car
2. 具體的實現
  1. 工程 honda_car 和 tesla_car
  2. 工程依賴了spi_interface
    pom.xml
  3. 有一個實現類,實現了標準
    HondaCar implements Car
    TeslaCar implements Car
  4. 還有一個配置文件
    1). 在類路徑classpath下
    resources/META-INF/services
    2). 文件名: 接口的全限定名
    com.itheima.Car
    3). 文件內容: 實現類的全限定名
    com.itheima.impl.HondaCar
3. 調用
  1. 工程 spi_test
  2. 工程依賴了 honda_car 和 tesla_car
  3. 測試類 SpiTest

測試類代碼

 # ServiceLoader<Car> cars = ServiceLoader.load(Car.class);加載接口實現1. 加載當前工程依賴的所有工程 classpath:META-INF/services目錄下跟當前接口參數同名的文件(classpath:META-INF.services/com.itheima.Car文件)2. 當前案例依賴了兩個工程,那么這兩個工程的配置文件都會被讀取到honda_car===META-INF.services/com.itheima.Car文件中的com.itheima.impl.HondaCartesla_car===META-INF.services/com.itheima.Car文件中的com.itheima.impl.TeslaCar注意:配置文件名必須是實現的接口全路徑,配置文件中書寫實現類的全路徑3. 通過反射創建接口文件中配置的實例Class clazz= Class.forName("com.itheima.impl.TeslaCar");Car car =  clazz.newInstance();

ServiceLoader類介紹

  1. ServiceLoader功能和ClassLoader功能類似,能裝載類文件,但是使用時是有區別的
  2. ServiceLoader裝載的是一系列有某種共同特征的實現類(類實現同一個接口,在實現類的工程中的resources目錄下存在META-INF/services目錄下接口同名的文件),即這些類實現接口或者抽象類。而ClassLoader是可以加載任何類的類加載器;
  3. ServiceLoader加載時需要特殊的配置:
    1. 在類路徑:classpath:META-INF/services/接口全路徑文件
    2. 在文件中配置實現類全路徑com.itheima.impl.HondaCar
  4. ServiceLoader還實現了Iterable接口,可以進行迭代
  5. 原理:在ServiceLoader.load的時候,根據傳入的接口Class對象,遍歷META-INF/services目錄下的以該接口命名的文件中的所有類,將創建實現類的對象返回。

SPI介紹

全稱Service Provider Interface,是Java提供的一套用來被第三方實現或者擴展的API,它可以用來啟用框架擴展和替換組件
Java的SPI機制就是將一些類信息寫在約定的文件中,然后由特定的類加載器ServiceLoader加載解析文件獲取資源
Java SPI 基于"接口編程+策略模式+配置文件(約定)"組合實現的動態加載機制
運用場景

場景說明
數據庫驅動數據庫驅動加載接口實現類的加載 JDBC加載不同類型數據庫的驅動
日志門面SLF4J接口實現類加載SLF4J加載不同提供商的日志實現類
SpringSpring中大量使用了SPI,比如:對servlet3.0規范對ServletContainerInitializer的實現、自動類型轉換Type Conversion SPI(Converter SPI、Formatter SPI)等
DubboDubbo中也大量使用SPI的方式實現框架的擴展, 不過它對Java提供的原生SPI做了封裝,允許用戶擴展實現Filter接口
SpringBootSpringBoot基于SPI思想實現自動裝配

SPI練習JDBC4.0免注冊驅動原理

public class JdbcDemo {public static void main(String[] args) throws Exception {//1.加載驅動
//        Class.forName("com.mysql.jdbc.Driver");//2.獲取連接Connection connection = DriverManager.getConnection("jdbc:mysql:///dbvue", "root", "1234");System.out.println(connection);}
}
//DriverManager類源碼:
public class DriverManager {//靜態代碼塊static {loadInitialDrivers();println("JDBC DriverManager initialized");}private static void loadInitialDrivers() {.....AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {//spi/*1.java.sql.Driver 是一個接口2.java.sql.Driver接口實現類,com.mysql.jdbc.Driver使用SerciveLoader類加載器調用方法獲取java.sql.Driver接口的實現類對象放到LoadedDrivers中*/ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(java.sql.Driver.class);Iterator<Driver> driversIterator = loadedDrivers.iterator();try{while(driversIterator.hasNext()) {driversIterator.next();}} catch(Throwable t) {// Do nothing}return null;}});......}
}

Servlet實現方式三 ServletContainerInitializer

前倆種方式是注解和xml
第三種就是spi方式,后面學習的框架底層就是采用這種方式
ServletContainerInitializer 是 Servlet 3.0 新增的一個接口,主要用于在容器啟動階段通過編程風格注冊Filter, Servlet以及Listener,以取代通過web.xml配置注冊。這樣就利于開發內聚的web應用框架.
運行原理

  1. ServletContainerInitializer接口的實現類通過java SPI聲明自己是ServletContainerInitializer 的提供者.
  2. web容器啟動階段依據java spi獲取到所有ServletContainerInitializer的實現類,然后執行其onStartup方法.
  3. 在onStartup中通過編碼方式將組件servlet加載到ServletContext

小結
ServletContainerInitializer 在web容器啟動時為提供給第三方組件機會做一些初始化的工作,例如注冊servlet或者filter等,servlet規范中通過ServletContainerInitializer實現此功能。每個框架要使用ServletContainerInitializer就必須在對應的jar包的META-INF/services 目錄創建一個名為javax.servlet.ServletContainerInitializer的文件,文件內容指定具體的ServletContainerInitializer實現類,那么,當web容器啟動時就會運行這個初始化器做一些組件內的初始化工作
image.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/10083.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/10083.shtml
英文地址,請注明出處:http://en.pswp.cn/web/10083.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

idea使用前的全局配置,一次配置,多次使用

前提&#xff1a;每次導入一個新的項目&#xff0c;就需要重新設置編碼、maven、jdk、git版本等信息。實際每個項目所用到的配置信息是一致的&#xff0c;除非換一家公司&#xff0c;不然不會改動到這些內容。 idea版本&#xff1a;2024.1.1 1.1、全局Maven配置 IDEA啟動頁面…

微火一文盤點:為何全域運營系統會成為創業新風口?

當前&#xff0c;微火全域運營已經成為創業的新風口&#xff0c;想要做微火全域運營服務商的創業者數量日益增多。據目前了解到的最新消息&#xff0c;微火全域運營系統的市場占有率已經超過了48%&#xff0c;并且還在持續不斷地上漲中。 所謂微火全域運營系統&#xff0c;就是…

InLine Chat功能優化對標Github Copilot,CodeGeeX帶來更高效、更直觀的編程體驗!

VSCode中的CodeGeeX 插件上線InLine Chat功能后&#xff0c;收到不少用戶的反饋&#xff0c;大家對行內交互編程這一功能非常感興趣。近期我們針對這個功能再次進行了深度優化&#xff0c;今天詳細介紹已經在VSCode插件v2.8.0版本上線的 CodeGeeX InLine Chat功能&#xff0c;以…

藍橋杯成績已出

藍橋杯的成績早就已經出來了&#xff0c;雖然沒有十分驚艷 &#xff0c;但是對于最終的結果我是心滿意足的&#xff0c;感謝各位的陪伴&#xff0c;關于藍橋杯的刷題筆記我已經堅持更新了49篇&#xff0c;但是現在即將會告別一段落&#xff0c;人生即將進入下一個規劃。我們一起…

Spring框架學習筆記(一):Spring基本介紹(包含IOC容器底層結構)

1 官方資料 1.1 官網 https://spring.io/ 1.2 進入 Spring5 下拉 projects, 進入 Spring Framework 進入 Spring5 的 github 1.3 在maven項目中導入依賴 <dependencies><!--加入spring開發的基本包--><dependency><groupId>org.springframework<…

jni 返回二維byte數組

在JNI中返回二維byte數組&#xff0c;你需要在Java中準備一個相應的二維數組來接收這個返回值。在JNI層面&#xff0c;你可以創建一個二維的byte數組&#xff0c;并使用GetByteArrayRegion和SetByteArrayRegion來操作它。 以下是一個簡單的例子&#xff1a; public class Jni…

基于STC12C5A60S2系列1T 8051單片機實現一主單片機與一從單片機進行雙向串口通信功能

基于STC12C5A60S2系列1T 8051單片機實現一主單片機與一從單片機進行雙向串口通信功能 STC12C5A60S2系列1T 8051單片機管腳圖STC12C5A60S2系列1T 8051單片機串口通信介紹STC12C5A60S2系列1T 8051單片機串口通信的結構基于STC12C5A60S2系列1T 8051單片機串口通信的特殊功能寄存器…

QT---day5,通信

1、思維導圖 2、TCp 服務器 #ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> #include <QTcpServer> #include <QList> #include <QTcpSocket> #include <QMessageBox> #include <QDebug> #include <QTcpServer> QT_B…

鐳速實現利用Libarchive實現高效、智能的文件傳輸和管理

在前一篇報道中&#xff0c;我們闡述了Libarchive這一開源庫的強大功能&#xff0c;它專門用于處理歸檔文件。通過整合Libarchive&#xff0c;鐳速在包括Windows和Linux在內的多個操作系統上提供了在線解壓縮服務&#xff0c;為企業構建了一個既強大又安全的文件傳輸系統&#…

【代碼分享】使用HTML5的Canvas繪制編碼說明圖片

最急在工作中遇到一個需求&#xff0c;根據給定的編碼生成編碼說明&#xff0c;像下面這樣的效果。 不同含義的編碼用橫杠分割&#xff0c;然后每個編碼下面用箭頭指明具體的含義。下面是我使用canvas實現的代碼。具體的編碼寬度大家可以根據實際情況進行調整&#xff0c;目前…

Ranger 面試題及答案整理,最新面試題

Ranger 的安全模型是如何設計的&#xff1f; Ranger的安全模型設計主要基于訪問控制和安全策略的管理&#xff0c;它通過以下幾個關鍵組件實現&#xff1a; 1、策略管理&#xff1a; Ranger 提供了一個中央管理平臺&#xff0c;用于定義、更新和管理安全策略。這些策略根據資…

基于RT-Thread的HC-SR04超聲波驅動

前言 本次驅動用的是這款超聲波&#xff0c;超聲波的驅動大同小異&#xff0c;均可參考 一、引腳定義 引腳功能VCC接直流5V電TRIG接外部電路的TRIG端&#xff0c;向此引腳輸入10us以上的高電平可觸發超聲波測距ECHO接外部電路的ECHO端&#xff0c;測距結束時該引腳會輸出一…

Python框架Django入門教程

Django 是一個使用 Python 編程語言開發的、免費且開源的 Web 應用框架。它遵循 "DRY&#xff08;Dont Repeat Yourself&#xff09;" 原則&#xff0c;旨在簡化創建功能豐富的、高效率的 Web 網站。Django 提供了模型-視圖-控制器&#xff08;MVC&#xff09;架構的…

時尚圈的節制美學 — 奧柔拉 AVRALA的獨特設計理念

在這個多元化的時代&#xff0c;女性正在經歷一場前所未有的角色變革。她們不再僅僅滿足于傳統的社會角色&#xff0c;而是勇敢地追求個人職業發展和自我實現。在這樣的背景下&#xff0c;服飾不僅僅是外在的裝飾&#xff0c;更是內心故事的講述者、個性自我的表達者、身份歸屬…

KaiOS Data PDN 數據建立流程

代碼邏輯 APN創建 在 DataCallManager.jsm中,會對所有apnsetting創建一個datacall,其中會包含dataprofile的成員(通過apn參數來創建),在之后的流程用于直接發送到modem建立PDN。 PDN建立 1、DataCallManager.jsm -dcInterface.setupDataCall //RILNetworkInterface.c…

C語言內存泄漏及檢測方法

目錄 1. 內存泄漏概述 1.1 內存泄漏定義 1.2 內存泄漏的危害 1.3 內促泄漏的原因 2. C語言中的內存管理 2.1 C語言內存分配方式 2.2 C語言內存管理函數 2.3 動態內存管理注意事項 3. 內存泄漏的檢測與定位 3.1 內存泄漏檢測工具 3.2 內存泄漏定位方法 3.3 內存泄漏…

NX/UG二次開發—3D幾何—多邊形內部最大圓

多邊形內部最大圓&#xff0c;為什么不能說最大內切圓&#xff1f;如果正方形或正凸多邊形&#xff0c;最大內部圓是與邊相切的&#xff0c;但對于不規則多邊形&#xff0c;很多情況是正好經過一些凹點。 本次介紹在NX中計算封閉邊界內部最大圓&#xff1a; 1、首先按順序排序…

Spring、SpringMVC

一、Spring框架中的單例Bean是線程安全的嗎&#xff1f; 【默認單例的情況下】Spring Bean并沒有可變的狀態&#xff08;如Service類和DAO類&#xff09;&#xff0c;即只能查不能改&#xff0c;所以沒有并發問題&#xff0c;所以某種程度上來說Spring的單例Bean是線程安全的。…

【ZZULI數據結構實驗】壓縮與解碼的鑰匙:赫夫曼編碼應用

&#x1f4c3;博客主頁&#xff1a; 小鎮敲碼人 &#x1f49a;代碼倉庫&#xff0c;歡迎訪問 &#x1f680; 歡迎關注&#xff1a;&#x1f44d;點贊 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f30f; 任爾江湖滿血骨&#xff0c;我自踏雪尋梅香。 萬千浮云遮碧…