後臺許可權管理專案總結
最近做了一個後臺的許可權管理專案,沒有用到springSecurity,也沒有用到shiro,純粹是用原生態的寫法做的,有點粗糙,但是思想沒變,這裡記錄一下自己的心得。
首先是設計資料庫的表,一共5張表,分別為使用者表,角色表,許可權表,使用者角色關係表,角色許可權關係表。這裡遇到的最大的坑就一個,導致後臺程式被大改,這裡給自己警醒,場景是這樣的,當我手動從資料庫中刪除一條資料的時候,程式碼debug除錯的時候竟然查到我刪掉的資料,這是一件很詭異的事情,後來上網查了一些這方面的資料,雖然沒查到我這個問題的原因,但是解決方案算是找到了,即為:一張表除了有一個數據庫自帶的自增主鍵,還要設定一個邏輯主鍵,可以用UUID作為主鍵。第二個問題是專案中的刪除很少用到delete語句,一般都是軟刪除,即為新增一個欄位isDelete(0表示刪除,1表示存在),所以刪除即為更新一下這個欄位即可。
然後是後臺程式方面:第一個肯定是登入操作,判斷邏輯還是有點繞的,首先根據使用者名稱查該使用者是否存在,如果不存在,即返回給前端錯誤碼和錯誤資訊;如果查到的話,再將查到的使用者的密碼和前臺傳過來的密碼進行比對,如果不等,那麼進行三次機會重新輸入,如果都輸入錯誤,則將該使用者的狀態更新為鎖定,表示該使用者暫時不能登入;如果該使用者密碼比對正確或者三次機會中有一次機會輸入正確,則表示該使用者登陸成功,更新該使用者資料庫密碼錯誤次數為初始值。然後用該使用者主鍵根據角色使用者關係表查詢該使用者的角色,為一個集合,再用該角色的主鍵根據角色許可權關係表查詢該角色的許可權資訊,為一個list,然後用該使用者的唯一標識,比如該使用者的編號,拼接一個隨機數,生成一個token,然後將該使用者資訊和許可權的list集合以及這個token封裝到一個物件中,返給前臺,還將這個資訊存在redis快取中,當然還有個自定義的本地快取,怎麼建立,這樣來:建立一個工具類,例如LocalCache類,然後在這個類中定義一個static的集合,例如:
private static List<快取儲存的物件> myList = new ArrayList<>();
然後是使用者類和角色類的增刪改查,刪除資料改isDelete狀態,修改資料後返回修改後的資料資訊,這些沒什麼好說的,新增資料的時候要注意先查一下,如果資料庫中有這條資料的話,那麼不讓增加。程式碼需要try{}catch(){},這樣出現錯誤也能夠捕捉的到。區別許可權的選單級和按鈕級,這個很好區別,根據Controller的@RequestMapping("")中的path很好判斷。例如:
然後還有根據日期區間進行查詢,例如查詢當天的資料,例如查詢2018-12-12 00:00:00到2018-12-12 23:59:59這個日期區間的資料,但是前臺傳給你的只有2018-12-12日這個格式的資料,因此需要你進行轉換為你所需要的日期形式,如下:
package com.Jevin.controller;
import org.junit.Test;
import java.util.Calendar;
import java.util.Date;
public class DateUtil {
/**
* 獲取日期的00:00:00
* @param startDate
* @return
*/
public static Date getStartTime(Date startDate){
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.set(Calendar.HOUR_OF_DAY,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
return calendar.getTime();
}
/**
* 獲取日期的23:59:59
* @param endDate
* @return
*/
public static Date getEndTime(Date endDate){
Calendar calendar = Calendar.getInstance();
calendar.setTime(endDate);
calendar.set(Calendar.HOUR_OF_DAY,23);
calendar.set(Calendar.MINUTE,59);
calendar.set(Calendar.SECOND,59);
return calendar.getTime();
}
@Test
public void test(){
System.out.println(getEndTime(new Date()));
}
}
然後就是物件封裝的問題,即為同一個類,我們需要將其拆分為三個物件,一個用來接收前臺的引數,一個物件用來和資料庫進行互動,一個物件用來返回給前端。
然後是過濾器的問題,到目前為止我已經試過4中過濾器了:
第一種是springAOP過濾器:
package com.Jevin.controller;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class PermissionInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("進入過濾器");
return methodInvocation.proceed();
}
}
配置檔案
<!-- 配置攔截器的bean -->
<bean id="permissionInterceptor" class="com.Jevin.controller.PermissionInterceptor"/>
<!-- springAOP方法攔截器配置 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>userController</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>permissionInterceptor</value>
</list>
</property>
</bean>
<!-- 任意一個類的bean -->
<bean id="userController" class="com.Jevin.controller.UserController"/>
第二種是jboss.resteasy中的CorsFilter
匯入一下依賴
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jaxrs</artifactId> <version>3.0.12.Final</version> </dependency>
package com.Jevin.controller;
import org.jboss.resteasy.plugins.interceptors.CorsFilter;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
@PreMatching
public class PermissionFilter extends CorsFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
System.out.println("requestContext");
boolean flag = false;
if(!flag){
Result result = new Result();
result.setResponseCode("000");
result.setReserveMsg("error message");
Response.ResponseBuilder builder = Response.status(200).entity(result);
builder.type(MediaType.APPLICATION_JSON);
requestContext.abortWith(builder.build());
}
}
}
其中Result是一個結果集物件,主要用來返回給前端響應結果的。
第三種是javax.servlet.Filter中的doFilter()方法過濾器,
第四種是org.springframework.web.servlet.HandlerInterceptor,
這兩種比較常見,在網上隨處可以查到一大把,這裡就不說了。
然後是使用者狀態,比方說0表示正常,1表示銷戶,2表示鎖定,0,1,2是插入資料庫中的資料;正常,銷戶,鎖定是返回給前端的使用者狀態資訊,這裡最好用enum列舉型別來做,如下:
package com.Jevin.controller;
public enum UserStateEnum {
NORMAL("0","正常"),
CANCEL("1","登出"),
LOCK("2","鎖定");
private String code;
private String status;
UserStateEnum(String code,String status){
this.code=code;
this.status=status;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
大致自己所走過的彎路,所總結的也就這些了,希望給道友一些友好的提示。。。