文章目錄
- 第一章:授權操作
- 第一節:經典權限5張表的關系分析
- 1、資料庫模型關系圖
- 2、使用者角色關系表
- 3、角色權限關系表
- 4、修改使用者SysUser實體
- 5、修改角色Role實體
- 6、修改權限Permission實體
- 第二節:檢視使用者的角色詳情功能
- 1、頁面入口
- 2、編寫Controller
- 3、編寫Service
- 4、編寫Dao
- 編寫userDao
- 編寫RoleDao(user下有role)
- 編寫PermissionDao(Role下有permission)
- 5、修改前端user-show.jsp
- 第三節:為使用者配置設定角色-角色清單資料回顯
- 1、頁面入口
- 2、編寫Controller
- 3、頁面回顯資料(user-role-add.jsp)
- 第四節:為使用者配置設定角色-更新關系到使用者角色中間表
- 1、頁面入口
- 2、編寫Controller
- 3、編寫Service
- 4、編寫Dao
- 第五節:為角色添權重限資料回顯(和user添加role雷同)
- 1、頁面入口
- 2、編寫Controller
- 3、編寫Service
- 4、編寫Dao
- 5、前端頁面(role-permission-add.jsp)
- 第六節:為角色添權重限-實際儲存即往中間表插入記錄(和user添加role雷同)
- 1、頁面入口
- 2、編寫Controller
- 3、編寫service
- 4、編寫dao
- 第七節:為使用者設定真正的角色
- 第二章:授權後的安全控制
- 第一節:在JSP頁面控制菜單權限(不顯示UI)
- 1、spring-security.xml配置檔案
- 第二節:在伺服器端控制權限(攔截請求 防止使用者直接輸入url通路)
- 1、修改spring-mvc.xml配置
- 2、在需要進行控制的Controller上添加@Secured注解
- 3、更換預設403 forbidden界面
- 第三章:系統日志功能
- 第一節:AOP記錄日志
- 1、日志表sys_log和實體Log
- 2、springmvc.xml配置檔案中開啟aop的自動代理
- 3、在web.xml中配置監聽request對象的監聽器
- 4、編寫切面類(切面類内部有增強)
- 5、Service代碼實作
- 6、Dao代碼實作
- 第二節 查詢日志
- 1、頁面入口
- 2、編寫Controller
- 3、編寫service
- 4、編寫dao
- 5、修改domain
- 6、修改頁面
第一章:授權操作
第一節:經典權限5張表的關系分析
1、資料庫模型關系圖

2、使用者角色關系表
多對多的關系:就是兩個一對多
一對多:在一的方向添加一個集合屬性即可
-- 使用者角色關系表 多對多 引入中間表
CREATE TABLE sys_user_role(
userId number,
roleId number,
PRIMARY KEY(userId,roleId), --聯合主鍵:兩個不能同時一樣
FOREIGN KEY (userId) REFERENCES sys_USER(id),
FOREIGN KEY (roleId) REFERENCES sys_role(id)
)
3、角色權限關系表
CREATE TABLE sys_role_permission(
permissionId number,
roleId number,
PRIMARY KEY(permissionId,roleId),
FOREIGN KEY (permissionId) REFERENCES sys_permission(id),
FOREIGN KEY (roleId) REFERENCES sys_role(id)
)
4、修改使用者SysUser實體
@Data
public class SysUser {
private Long id;
private String username;
private String email;
private String password;
private String phoneNum;
private int status;
//一個使用者對應多個角色
private List<Role> roles = new ArrayList<>();//new出來 防止空指針
}
5、修改角色Role實體
@Data
public class Role {
private Integer id;
private String roleName;
private String roleDesc;
//一個角色被多個使用者所擁有
private List<SysUser> users = new ArrayList<>();
//一個角色擁有多個權限
private List<Permission> permissions = new ArrayList<>();
}
6、修改權限Permission實體
@Data
public class Permission {
private Integer id;
private String permissionName;
private String url;
private Integer pid;//寫簡單的pid 不能寫Permission對象 随便想想也是死循環
//一個權限被多個角色擁有
private List<Role> roles=new ArrayList<>();
}
第二節:檢視使用者的角色詳情功能
1、頁面入口
<a href="${pageContext.request.contextPath}/user/details?userId=${user.id}" class="btn bg-olive btn-xs">詳情</a>
2、編寫Controller
/**
* 查詢某使用者的詳情功能
* 使用者有哪些角色 角色分别有哪些權限
* @param userId
* @return
*/
@RequestMapping("/details")
public ModelAndView details(Integer userId){
LogUtils.print("使用者詳情:"+userId);
//查詢資料--使用者詳情
SysUser user=userService.findById(userId);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
modelAndView.setViewName("user-show");
return modelAndView;
}
3、編寫Service
findById(Integer userId);
@Override
public SysUser findById(Integer userId) {
return userdao.findById(userId);
}
4、編寫Dao
編寫userDao
@Select("select * from sys_user where id = #{userId}")
@Results({
@Result(id=true,property = "id",column = "id"),//主鍵id 最好都加上 否則後端擷取id為null
@Result(property = "roles",column = "id", //還是本張表主鍵id,因為是根據本張表主鍵id關聯到role的
//根據userId查詢角色清單
// cn.ahpu.dao.RoleDao.findRolesByUserId
many = @Many(select = "cn.ahpu.dao.RoleDao.findRolesByUserId"))
})
SysUser findById(Integer userId);
編寫RoleDao(user下有role)
@Select("select r.* from sys_user_role ur,sys_role r where ur.roleid=r.id and ur.userid=#{userId}")
@Results({
@Result(id=true,property = "id",column = "id"),//主鍵id 最好加上 否則id隻能用一次 後端查id就是null了
@Result(property = "permissions",column = "id", //還是本張表主鍵id,因為是根據本張表主鍵id關聯到role的
many = @Many(select = "cn.ahpu.dao.PermissionDao.findPermissionsByRoleId"))
})
List<Role> findRolesByUserId(Integer userId);
編寫PermissionDao(Role下有permission)
@Select("select p.* from sys_role_permission rp,sys_permission p where rp.roleid=#{roleId} and rp.permissionid=p.id")
List<Permission> findPermissionsByRoleId(Integer roleId);
5、修改前端user-show.jsp
<thead>
<tr>
<th>名稱</th>
<th>描述</th>
</tr>
</thead>
<tr data-tt-id="0">
<td colspan="2">${user.username}</td>
</tr>
<tbody>
<c:forEach items="${user.roles}" var="role" varStatus="i">
<tr data-tt-id="${role.id}" data-tt-parent-id="0">
<td>${role.roleName }</td>
<td>${role.roleDesc }</td>
</tr>
<%--子标簽的父id要唯一對應 得用${i.count}了 }
若dao中id@Result()裡id都單獨配置了
那麼id可以多次使用 将i.count全部換成 role.id也不錯
--%>
<c:forEach items="${role.permissions}" var="permission">
<tr data-tt-id="${role.id}-${permission.id}" data-tt-parent-id="${role.id}">
<td>${permission.permissionName}</td>
<td>${permission.url}</td>
</tr>
</c:forEach>
</c:forEach>
</tbody>
第三節:為使用者配置設定角色-角色清單資料回顯
1、頁面入口
2、編寫Controller
@RequestMapping("/addRoleToUserUI")
public ModelAndView addRoleToUserUI(Integer userId){
LogUtils.print("addRoleToUserUI:"+userId);
//所有角色
List<Role> roles = roleService.findAll();
//目前使用者擁有的角色 直接将目前使用者傳過去也行 延遲加載還能起點作用
SysUser user = userService.findById(userId);
//友善選中已有的 換種寫法
List<Role> userOwnedRoles = user.getRoles();
//把該使用者擁有的角色id存到list放到前端
//id變成一個list 前端友善判斷該id是否在數組中 el ${fn:contains(ids,id)}
List<Integer> ids=new ArrayList<>();
for (Role role : userOwnedRoles) {
ids.add(role.getId());
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("roles",roles);
modelAndView.addObject("ids",ids);
//真正執行添加業務時需要userId 是以也需要傳過去
modelAndView.addObject("userId",user.getId());//user.getId()而不直接寫userId "永遠使用最後一次得到的資料"
modelAndView.setViewName("user-role-add");
return modelAndView;
}
3、頁面回顯資料(user-role-add.jsp)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<section class="content">
<input type="hidden" name="userId" value="${userId}"><%--使用者id隐藏域--%>
<table id="dataList"
class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class=""style="padding-right:">
<input id="selall"
type="checkbox" class="icheckbox_square-blue"></th>
<th class="sorting_asc">ID</th>
<th class="sorting">角色名稱</th>
<th class="sorting">角色描述</th>
</tr>
</thead>
<tbody>
<c:forEach items="${roles}" var="role">
<tr>
<td><input name="ids" type="checkbox" value="${role.id}"
<%--<c:if test="${fn:contains(ids, role.id)}">checked="checked"</c:if>--%>
<%--大神更牛的寫法--%>
${fn:contains(ids, role.id)?"checked":" "}
></td>
<td>${role.id}</td>
<td>${role.roleName }</td>
<td>${role.roleDesc}</td>
</tr>
</c:forEach>
</tbody>
</table>
第四節:為使用者配置設定角色-更新關系到使用者角色中間表
1、頁面入口
2、編寫Controller
/**
* 給指定使用者添加指定角色
* @param userId 需要添加角色的使用者id
* @param ids 添加角色的id數組
* @return
*/
@RequestMapping("/addRolesToUser")
public String addRolesToUser(Integer userId,Integer[] ids){
userService.addRolesToUser(userId,ids);
return "redirect:/user/findAll";
}
3、編寫Service
接口
/**
* 添加角色清單到使用者
* @param userId
* @param ids
*/
void addRolesToUser(Integer userId, Integer[] ids);
實作
@Override
public void addRolesToUser(Integer userId, Integer[] ids) {
//先清空該使用者擁有的所有角色
userdao.delRolesFromUser(userId);
if(ids!=null){
for (Integer roleId : ids) {
userdao.saveRoleToUser(userId,roleId);
}
}
}
4、編寫Dao
/**
* 清空使用者原來有的所有角色
* @param userId
*/
@Delete("delete from sys_user_role where userId=#{userId}")
void delRolesFromUser(Integer userId);
/**
* 為使用者添加一個角色
* @param userId
* @param roleId
*/
@Insert("insert into sys_user_role values(#{param1},#{param2})")
void saveRoleToUser(Integer userId, Integer roleId);
第五節:為角色添權重限資料回顯(和user添加role雷同)
1、頁面入口
<a href="${pageContext.request.contextPath}/role/addPermissionsToRoleUI?roleId=#{role.id}" class="btn bg-olive btn-xs">添權重限</a>
2、編寫Controller
/**
* 添權重限到角色的資料回顯
* @param roleId
* @return
*/
@RequestMapping("/addPermissionsToRoleUI")
public ModelAndView addPermissionsToRoleUI(Integer roleId){
LogUtils.print(roleId);
//擷取所有權限
List<Permission> permissions = permissionService.findAll();
//擷取角色已有權限id清單
Role role = roleService.findById(roleId);
List<Permission> rolePermissions = role.getPermissions();
List<Integer> ids=new ArrayList<>();
for (Permission p : rolePermissions) {
ids.add(p.getId());
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("permissions",permissions);
modelAndView.addObject("ids",ids);
modelAndView.addObject("roleId",roleId);
modelAndView.setViewName("role-permission-add");
return modelAndView;
}
3、編寫Service
findById(Integer roleId);
@Override
public Role findById(Integer roleId) {
return roleDao.findById(roleId);
}
4、編寫Dao
@Select("select * from sys_role where id=#{roleId}")
@Results({
@Result(property = "id",column = "id"),
@Result(property = "permissions",column = "id",
many=@Many(select = "cn.ahpu.dao.PermissionDao.findPermissionsByRoleId",fetchType = FetchType.LAZY)
)
})
Role findById(Integer roleId);
5、前端頁面(role-permission-add.jsp)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<form
action="${pageContext.request.contextPath}/role/addPermissionToRole.do"
method="post">
<!-- 正文區域 -->
<section class="content"> <input type="hidden" name="roleId"
value="${roleId}">
<table id="dataList"
class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class=""style="padding-right:">
<input id="selall"
type="checkbox" class="icheckbox_square-blue"></th>
<th class="sorting_asc">ID</th>
<th class="sorting">權限名稱</th>
<th class="sorting">URL</th>
</tr>
</thead>
<tbody>
<c:forEach items="${permissions}" var="permission">
<tr>
<td><input name="ids" type="checkbox" value="${permission.id}"
${fn:contains(ids, permission.id)?"checked":""}
></td>
<td>${permission.id}</td>
<td>${permission.permissionName }</td>
<td>${permission.url}</td>
</tr>
</c:forEach>
</tbody>
</table>
<!--訂單資訊/--> <!--工具欄-->
<div class="box-tools text-center">
<button type="submit" class="btn bg-maroon">儲存</button>
<button type="button" class="btn bg-default"
onclick="history.back(-1);">傳回</button>
</div>
<!--工具欄/--> </section>
<!-- 正文區域 /-->
</form>
第六節:為角色添權重限-實際儲存即往中間表插入記錄(和user添加role雷同)
1、頁面入口
2、編寫Controller
/**
* 為角色添權重限 動資料庫表
* @param roleId
* @param ids
* @return
*/
@RequestMapping("/addPermissionsToRole")
public String addPermissionsToRole(Integer roleId,Integer[] ids){
LogUtils.print(ids);
LogUtils.print(roleId);
roleService.addPermissionsToRole(roleId,ids);
return "redirect:/role/findAll";
}
3、編寫service
void addPermissionsToRole(Integer roleId, Integer[] ids);
/**
* 為角色roleId 添加 ids這麼多的權限
* @param roleId
* @param ids
*/
@Override
public void addPermissionsToRole(Integer roleId, Integer[] ids) {
//删除roleId所有權限
roleDao.delPermissionsFromRole(roleId);
if(ids!=null){
for (Integer permissionId : ids) {
roleDao.savePermissionToRole(roleId,permissionId);
}
}
}
4、編寫dao
@Delete("delete from sys_role_permission where roleid=#{roleId}")
void delPermissionsFromRole(Integer roleId);
/**
* 注意參數順序
* @param roleId
* @param permissionId
*/
@Insert("insert into sys_role_permission values(#{param2},#{param1})")
void savePermissionToRole(Integer roleId, Integer permissionId);
第七節:為使用者設定真正的角色
修改UserServiceImpl的loadUserByUsername方法,為使用者設定真正的角色
/**
* 通過使用者名 得到使用者對象
* 建立使用者詳情對象,傳回
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根據使用者名擷取使用者(SysUser)對象--同時查詢相應角色
SysUser sysUser = userdao.findByUsername(username);
if(sysUser==null) return null;
/* 添加的都是假的角色對象 真正的角色對象需要到資料庫内查
//配置檔案裡沒有指定角色了 需要自己建立角色對象
//建立角色的集合對象
Collection<GrantedAuthority> authorities=new ArrayList<>();
//建立臨時角色對象 正常情況下應該是資料庫角色表中查的
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
//對象添加到集合中
authorities.add(grantedAuthority);
//User是安全架構内實作了UserDetails接口的一個類
//第三個參數是:角色清單對象 (此處角色名ROLE_USER自己定義 xml裡需要這個名字)
//{noop}字首表示不加密 該把不加密去掉了*/
//添加資料庫裡真正的角色對象
Collection<GrantedAuthority> authorities=new ArrayList<>();
//登入時授權給使用者 有哪些權限就授予哪些權限
for (Role role : sysUser.getRoles()) {
//LogUtils.print(role.getRoleName());
//建立角色對象
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_"+role.getRoleName());
//添加角色對象到集合
authorities.add(grantedAuthority);
}
//使用者名 密碼 角色
UserDetails user = new User(sysUser.getUsername(),sysUser.getPassword(),authorities);
return user;
}
userdao.findByUsername(username);,加個一對多結果集映射,否則查不到使用者所擁有的權限
//根據使用者名查詢使用者對象 唯一對象(username必須唯一)
@Select("select * from sys_user where username = #{username} and status=1")
@Results({
@Result(id=true,property = "id",column = "id"),//主鍵id 最好都加上 否則後端擷取id為null
@Result(property = "roles",column = "id", //還是本張表主鍵id,因為是根據本張表主鍵id關聯到role的
many = @Many(select = "cn.ahpu.dao.RoleDao.findRolesByUserId",fetchType = FetchType.LAZY))
})
SysUser findByUsername(String username);
第二章:授權後的安全控制
第一節:在JSP頁面控制菜單權限(不顯示UI)
在JSP頁面中使用security:authorize标簽,可以控制菜單是否顯示。security:authorize标簽的 access=“hasAnyRole(‘ROLE_USER’,‘ROLE_ADMIN’)”。因為标簽的access使用的是表達式,是以需要将spring- security.xml配置檔案的use-expressions設定為true。
1、spring-security.xml配置檔案
1、使用表達式改為true: use-expressions=“true”
2、access不能直接寫權限名而要寫成:access="hasAnyRole(‘ROLE_USER’,‘ROLE_ADMIN’)”
表示擁有’ROLE_USER’,'ROLE_ADMIN’中任意一個權限就初步可以通路/**任意路徑(真正目的是啥權限都沒有時無法通路本網站任意未放行路徑)
3、前端jsp 先加上标簽庫 然後
系統管理UI用 <security:authorize access=“hasRole(‘ROLE_ADMIN’)”></security:authorize>包裹
基礎資料UI用<security:authorize access=“hasAnyRole(‘ROLE_ADMIN’,‘ROLE_USER’)”></security:authorize>包裹
jsp:
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<security:authorize access="hasRole('ROLE_ADMIN')">
<li class="treeview"><a href="#"> <i class="fa fa-cogs"></i>
<span>系統管理</span> <span class="pull-right-container"> <i
class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li id="system-setting"><a
href="${pageContext.request.contextPath}/user/findAll"> <i
class="fa fa-circle-o"></i> 使用者管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/role/findAll"> <i
class="fa fa-circle-o"></i> 角色管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/permission/findAll">
<i class="fa fa-circle-o"></i> 權限管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/pages/syslog-list.jsp"> <i
class="fa fa-circle-o"></i> 通路日志
</a></li>
</ul></li>
</security:authorize>
<%--ROLE_ADMIN和ROLE_USER都可以使用 換言之啥權限都沒有連基礎資料都不能通路--%>
<security:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_USER')">
<li class="treeview"><a href="#"> <i class="fa fa-cube"></i>
<span>基礎資料</span> <span class="pull-right-container"> <i
class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li id="system-setting"><a
href="${pageContext.request.contextPath}/product/findAll">
<i class="fa fa-circle-o"></i> 産品管理
</a></li>
<li id="system-setting"><a
href="${pageContext.request.contextPath}/order/findAll">
<i class="fa fa-circle-o"></i> 訂單管理
</a></li>
</ul></li>
</security:authorize>
第二節:在伺服器端控制權限(攔截請求 防止使用者直接輸入url通路)
雖然頁面菜單對不同角色顯示類不同的菜單,但是如果直接通路伺服器端的url還是可以通路到資源資訊的,是以好 需要對伺服器端的資源進行安全控制。
控制方式就是借助于Spring的AOP,對Controller的的通路進行權限的功能增強。 修改spring-security.xml配置檔案,添加aop的自動代理
1、修改spring-mvc.xml配置
添加配置:
<!--AOP 當下面一行的配置也放在spring-mvc.xml本檔案内時此配置可有可無
當下面一行配置放在spring-security.xml中 本配置必須有 開啟注解動态代理
-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<!--配置開啟security的注解支援 必須加上-->
<security:global-method-security secured-annotations="enabled"/>
沒辦法提示了,自己手動加: 複制後改下名字即可
2、在需要進行控制的Controller上添加@Secured注解
指定擁有哪些權限時方可通路本Controller,使用者任意一個權限即可
@Secured({"ROLE_ADMIN"})
public class UserController
@Secured({"ROLE_ADMIN"})
public class RoleController
@Secured({"ROLE_ADMIN"})
public class PermissionController
@Secured({"ROLE_ADMIN","ROLE_USER"})
public class ProductController
3、更換預設403 forbidden界面
spring-security.xml裡加一行配置
<security:access-denied-handler error-page="/failer.jsp"></security:access-denied-handler>
第三章:系統日志功能
第一節:AOP記錄日志
1、日志表sys_log和實體Log
sql語句
create sequence log_seq;
CREATE TABLE sys_log(
id number PRIMARY KEY,
visitTime DATE,
username VARCHAR2(50),
ip VARCHAR2(30),
method VARCHAR2(200)
)
實體類
SysLog.java
@Data
public class SysLog {
private Long id;
private Date visitTime;//通路時間
private String username;//通路者使用者名
private String ip;//通路者ip
private String method;//通路的全限定類名.方法
}
2、springmvc.xml配置檔案中開啟aop的自動代理
之前應該已經加過了
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
3、在web.xml中配置監聽request對象的監聽器
springmvc會自動将httpservletrequest放到IOC容器中 即springmvc不需要加此配置
其他架構不會 其他web層架構想要注入request就必須加此配置
<!--配置請求監聽器:當請求發生時,在容器中建立請求對象-->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
4、編寫切面類(切面類内部有增強)
spring-mvc.xml得多掃描一個包了
LogAop代碼實作
package cn.ahpu.log;
import cn.ahpu.domain.SysLog;
import cn.ahpu.domain.SysUser;
import cn.ahpu.service.LogService;
import cn.ahpu.utils.LogUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author 寒面銀槍
* @create 2020-05-16 16:53
*
* 注解配置AOP
* 提供一個類配置為切面類
* 切面=切入點+通知
* 通知類型
* 前置增強:@Before
* 後置增強:@AfterReturning
* 最終增強:@After
* 異常增強:@AfterThrowing
* 環繞增強:@Around
*
*/
//注意xml裡加上掃描log包
@Component
@Aspect
public class LogController {
@Autowired
LogService logService;
@Autowired
HttpServletRequest request;//隻有springmvc放到IOC中了 換一個架構可能就沒了
@Pointcut("execution(* cn.ahpu.controller.*.*(..))")
public void pointcut(){}
/**
* 環繞增強
* @param joinPoint 連接配接點對象--可以執行真實方法--隻在環繞增強中使用
* 連接配接點就是攔截的方法
*/
@Around("pointcut()") //織入
public Object around(ProceedingJoinPoint joinPoint){
//建立日志對象
SysLog sysLog = new SysLog();
//将日志對象封裝
//1.通路時間 visitTime
sysLog.setVisitTime(new Date());
//2.通路使用者名 username 安全架構内得到 注意是安全架構的User 不是自己寫SysUser
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
sysLog.setUsername(user.getUsername());
//3.通路ip 還是得得到request對象 仔細想想哪裡有? IOC容器裡肯定有 直接注入一下就行了嘛
String ipAddr = request.getRemoteAddr();
sysLog.setIp(ipAddr);
//4.通路全限定類名
//被攔截類的全限定類名
String className = joinPoint.getTarget().getClass().getName();
//方法名稱
String methodName = joinPoint.getSignature().getName();
sysLog.setMethod(className+"."+methodName);
//将日志對象存儲到資料庫
LogUtils.print(sysLog);
logService.save(sysLog);
try {
//執行真實的方法--必須傳回真實方法傳回值 否則所有方法被攔截 傳回值都不傳回 就不會跳轉了
return joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}
5、Service代碼實作
LogService
public interface LogService {
void save(SysLog sysLog);
}
@Service
public class LogServiceImpl implements LogService {
@Autowired
LogDao logDao;
@Override
public void save(SysLog log) {
logDao.save(log);
}
}
6、Dao代碼實作
public interface LogDao {
@Insert("insert into sys_log values(log_seq.nextval,#{visitTime},#{username},#{ip},#{method})")
void save(SysLog log);
}
第二節 查詢日志
1、頁面入口
2、編寫Controller
/**
* 查詢所有日志 分頁查詢
*/
@RequestMapping("/findAll")
public ModelAndView findAll(
@RequestParam(value = "currPage",required = false,defaultValue = "1") Integer currPage,
@RequestParam(value = "pageSize",required = false,defaultValue = "5") Integer pageSize
){
PageInfo<SysLog> pageHelper = logService.findAllByPageHelper(currPage, pageSize);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("pageHelper", pageHelper);
modelAndView.setViewName("syslog-list");
return modelAndView;
}
3、編寫service
public interface LogService {
void save(SysLog sysLog);
/**
* 查詢所有日志
* @return
*/
List<SysLog> findAll();
/**
* 分頁查詢所有
* @param currPage
* @param pageSize
* @return
*/
PageInfo<SysLog> findAllByPageHelper(Integer currPage, Integer pageSize);
}
@Override
public PageInfo<SysLog> findAllByPageHelper(Integer currPage, Integer pageSize) {
//指定分頁參數
PageHelper.startPage(currPage,pageSize);
//查詢全部 分頁參數已經被綁定到目前線程 攔截器根據參數幫你做到攔截
List<SysLog> logs = logDao.findAll();
//建立PageInfo對象 控制頁面最多顯示5個頁碼
PageInfo<SysLog> pageInfo = new PageInfo<>(logs, 5);
//傳回
return pageInfo;
}
4、編寫dao
@Select("select * from sys_log")
List<SysLog> findAll();
5、修改domain
@Data
public class SysLog {
private Long id;
private Date visitTime;//通路時間
private String visitTimeStr;
private String username;//通路者使用者名
private String ip;//通路者ip
private String method;//通路的全限定類名.方法
public String getVisitTimeStr() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
String timeStr = sdf.format(visitTime);
return timeStr;
}
}
6、修改頁面
<table id="dataList"
class="table table-bordered table-striped table-hover dataTable">
<thead>
<tr>
<th class=""style="padding-right:"><input id="selall"
type="checkbox" class="icheckbox_square-blue"></th>
<th class="sorting_asc">ID</th>
<th class="sorting">通路時間</th>
<th class="sorting">通路使用者</th>
<th class="sorting">通路IP</th>
<th class="sorting">通路方法</th>
</tr>
</thead>
<tbody>
<c:forEach items="${pageHelper.list}" var="syslog" varStatus="i">
<tr>
<td><input name="ids" type="checkbox"></td>
<td>${i.count}</td>
<td>${syslog.visitTimeStr }</td>
<td>${syslog.username }</td>
<td>${syslog.ip }</td>
<td>${syslog.method}</td>
</tr>
</c:forEach>
</tbody>
</table>
<!--資料清單/-->
<!--工具欄-->
<div class="pull-left">
<div class="form-group form-inline">
<div class="btn-group">
<button type="button" class="btn btn-default" title="重新整理"
onclick="window.location.reload();">
<i class="fa fa-refresh"></i> 重新整理
</button>
</div>
</div>
</div>
<div class="box-tools pull-right">
<div class="has-feedback">
<input type="text" class="form-control input-sm"
placeholder="搜尋"> <span
class="glyphicon glyphicon-search form-control-feedback"></span>
</div>
</div>
<!--工具欄/-->
</div>
<!-- 資料表格 /-->
</div>
<!-- /.box-body -->
<!-- .box-footer-->
<div class="box-footer">
<div class="pull-left">
<div class="form-group form-inline">
第${pageHelper.pageNum} 頁,
總共${pageHelper.pages} 頁,共${pageHelper.total} 條資料。 每頁
<select class="form-control" name="pageSize" id="pageSize" onchange="gotoPage(1)">
<%--前10個用循環寫 友善--%>
<c:forEach begin="1" end="10" var="i">
<option value="${i}">${i}</option>
</c:forEach>
<option value="15">15</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
<option value="50">50</option>
</select> 條
</div>
</div>
<div class="box-tools pull-right">
<ul class="pagination" id="gotoLi">
<%--超連結裡通路js函數 必須加字首javascript:--%>
<li><a href="javascript:gotoPage(1)" aria-label="Previous">首頁</a></li>
<%--prePage多友善--%>
<li><a href="javascript:gotoPage(${pageHelper.prePage})">上一頁</a></li>
<%--頁面上顯示幾個頁碼也簡單可控了 實在太友善了--%>
<c:forEach begin="${pageHelper.navigateFirstPage}" end="${pageHelper.navigateLastPage}" var="i">
<li><a href="javascript:gotoPage(${i})">${i}</a></li>
</c:forEach>
<li><a href="javascript:gotoPage(${pageHelper.nextPage})">下一頁</a></li>
<li><a href="javascript:gotoPage(${pageHelper.pages})" aria-label="Next">尾頁</a></li>
</ul>
</div>
</div>
<script type="text/javascript">
//方法寫在外面 會自動執行 注意先得給每個option加上value="xx" 不能沒有value屬性
//每頁顯示幾條的資料回顯 select option
$("#pageSize option[value=${pageHelper.pageSize}]").prop("selected","selected");
//跳轉頁面
function gotoPage(currPage) {
//頁面的越界檢查此處判斷也很友善
if(currPage<1||currPage>${pageHelper.pages}) return;
var pageSize=$("#pageSize").val();
location.href="${pageContext.request.contextPath}/log/findAll?currPage="+currPage+"&pageSize="+pageSize;
}
</script>