项目环境: eclipse tomcat mysql jdk1.7 maven
框架:ssm
以下代码复制可用
项目结构
自定义aop日志
1.自定义日志注解类
package com.utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 在使用Retention时必须要提供一个RetentionPolicy的枚举类型参数
// RetentionPolicy有三个枚举内容:CLASS RUNTIME SOURCE
// CLASS, //编译程序将Annotation储存于class档中,缺省
@Retention(RetentionPolicy.RUNTIME)
// RUNTIME //编译程序将Annotation储存于class当中,可由JVM读入(通过反射机制)。这个功能搭配反射是非常强大的
// @Target里面的ElementType是用来指定Annotation类型可以用在哪一些元素上的.说明一下:TYPE(类型), FIELD(属性),
// METHOD(方法), PARAMETER(参数), CONSTRUCTOR(构造函数),LOCAL_VARIABLE(局部变量),
// ANNOTATION_TYPE,PACKAGE(包),其中的TYPE(类型)是指可以用在Class,Interface,Enum和Annotation类型上.
@Target(ElementType.METHOD)
/**
* 自定义日志注解
* @作者 罗玲红
*
* @时间 2017年3月25日 下午3:50:09
*/
public @interface Loggable {
/**
* @func 操作类型:四种(INSERT, UPDATE, SELECT, DELETE)
*/
public String optType();
/**
* @func 描述
*/
public String describe();
/**
* @func 日志模块,不同模块的日志保存到不同的日志表中
*/
public String module();
}
2.记录日志的实体类
package com.entry;
import java.security.Timestamp;
/**
* 记录日志的实体类
* @作者 罗玲红
*
* @时间 2017年3月25日 下午10:28:40
*/
public class Log {
/**
* 记录日志的id
*/
private Integer id;
/**
* 操作时间
*/
private Timestamp optTime;
/**
* 操作人
*/
private String optMan;
/**
* 日志类型,比如CURD
*/
private String logType;
/**
* 描述
*/
private String desc;
/**
* 状态
*/
private String status;
/**
* 异常
*/
private String exception;
public String getException() {
return exception;
}
public void setException(String exception) {
this.exception = exception;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Timestamp getOptTime() {
return optTime;
}
public void setOptTime(Timestamp optTime) {
this.optTime = optTime;
}
public String getOptMan() {
return optMan;
}
public void setOptMan(String optMan) {
this.optMan = optMan;
}
public String getLogType() {
return logType;
}
public void setLogType(String logType) {
this.logType = logType;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public String toString() {
return "Log [id=" + id + ", optTime=" + optTime + ", optMan=" + optMan + ", logType=" + logType + ", desc="
+ desc + ", status=" + status + "]";
}
}
3.数据库中不同的日志模板
package com.finall;
/**
* 数据库中不同的日志模板
* @作者 罗玲红
*
* @时间 2017年3月25日 下午10:27:42
*/
public class LogModule {
/**
* 登陆日志表
*/
public static final String Login = "login_log";
/**
* 账户日志表
*/
public static final String Account="account_log";
/**
* 字典日志表
*/
public static final String Dictionary="dictionary_log";
/**
* 角色日志表
*/
public static final String Role="role_log";
/**
* 图书日志表
*/
public static final String Book="book_log";
/**
* 期刊日志表
*/
public static final String Journal="journal_log";
/**
* 借书卡日志表
*/
public static final String Borrower="borrower_log";
/**
* 借书日志表
*/
public static final String BorrowBooks="borrowBooks_log";
/**
* 押金日志表
*/
public static final String Deposit="deposit_log";
/**
* 还书日志表
*/
public static final String ReturnBook="returnBook_log";
/**
* 滞纳金日志表
*/
public static final String OverdueFine="overdueFine_log";
/**
* 损书还书日志表
*/
public static final String Damage="damage_log";
public static final String LossBook="lossbook_log";
}
4.数据库操作类型
package com.finall;
/**
* 数据库操作类型
* @作者 罗玲红
*
* @时间 2017年3月25日 下午10:28:13
*/
public class LogOptType {
/**
* 插入
*/
public static final String INSERT = "INSERT";
/**
* 修改
*/
public static final String UPDATE = "UPDATE";
/**
* 查询
*/
public static final String SELECT = "SELECT";
/**
* 删除
*/
public static final String DELETE = "DELETE";
/**
* 登陆
*/
public static final String LOGIN="LOGIN";
}
Log4j日志
log4j.rootLogger=debug,stdout,info,debug,error
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%-5p] [%d{HH:mm:ss}] %c - %m%n
#\u5E94\u7528\u4E8E\u63A7\u5236\u53F0
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
#Generate one file per hour
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=[%-5p] [%d{HH:mm:ss}] %c - %m%n
log4j.appender.info.datePattern='.'yyyy-MM-dd-HH
log4j.appender.info.Threshold = INFO
log4j.appender.info.append=true
log4j.appender.info.File=E:\\flowUnfyPay\\logs\\info.log
#Generate two file per hour
log4j.logger.debug=debug
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=[%-5p] [%d{HH:mm:ss}] %c - %m%n
log4j.appender.debug.datePattern='.'yyyy-MM-dd-HH-a
log4j.appender.debug.Threshold = DEBUG
log4j.appender.debug.append=true
log4j.appender.debug.File=E:\\flowUnfyPay\\logs\\debug.log
#Generate one file every day
log4j.logger.error=error
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=[%-5p] [%d{HH:mm:ss}] %c - %m%n
log4j.appender.error.datePattern='.'yyyy-MM-dd
log4j.appender.error.Threshold = ERROR
log4j.appender.error.append=true
log4j.appender.error.File=E:\\flowUnfyPay\\logs\\error.log
传递Json数据
1.所需要的jar包:
1.在springmvc.xml中配置
<!-- 配置项目中需要的jackson bean -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" p:ignoreDefaultModelOnRedirect="true">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
2.在java的使用
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountServiceImpl;
/**
* 得到列表分页数据
*
* @param nowPage
* 当前页
* @return
*/
@RequestMapping(value = { "/list/{nowPage}" }, method = RequestMethod.POST)
@ResponseBody
public Page<Account> json(@PathVariable("nowPage") Integer nowPage) {
Page<Account> page = accountServiceImpl.getList(nowPage, 7);
return page;
}
}
3.在页面的使用
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<head>
<title>信息页面</title>
<style>
.page-right{float:right;width:400px;height:50px;}
</style>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/page.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/demo.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/layui/css/layui.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/style.css" />
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/basictable.css" />
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/loginDialog.css">
<script src="${pageContext.request.contextPath}/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="<%=request.getContextPath() %>/js/page.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$.ajax({
type: "POST",
contentType : "application/json",
dataType: "json",
url: "<%=request.getContextPath()%>/account/query/1",
success: function (data) {
dis(data);
}
});
});
function dis(data){
$("#nowPage").val(data.nowPage);
$("#pageNum").val(data.pageNum);
$("#countPage").val(data.countPage);
$.each(data.rows, function(i, acc) {
$("#tbody").append("<tr><td>"+(acc.id)+"</td><td>"+(acc.account)+"</td><td>
< a οnclick='update("+(acc.id)+");'id='edit' class='layui-btn layui-btn-mini layui-btn-normal'>编辑</a>"+
"<a οnclick='del("+(acc.id)+");' id = 'del' data-id='1' data-opt='del' class='layui-btn layui-btn-danger layui-btn-mini'>删除</a></tr>");
});
table();
}
var url = "<%=request.getContextPath()%>/account/query"
function update(id) {
var href="${pageContext.request.contextPath}/account/getUpdate/"+id;
$("#updFormId").attr("action",href).submit();
}
function del(id){
if(confirm("确认要删除 "+ id +"吗?")){
var href ="${pageContext.request.contextPath}/account/del/"+id;
$("#delFormId").attr("action",href).submit();
return false;
}
}
</script>
</head>
<body>
<input id="pageNum" type="hidden" />
<input id="nowPage" type="hidden" />
<input id="countPage" type="hidden" />
<div class="container">
<div id="page">
<table id="table">
<blockquote class="layui-elem-quote">
<fieldset class="layui-elem-field">
<div align="right">
<a href="<%=request.getContextPath()%>/account/addList"
class="layui-btn layui-btn-small layui-btn-normal" id="add">
添加信息
</a>
<div class="layui-input-inline">
<input placeholder="请输入相关信息" class="layui-input">
</div>
<div style="float:left">
<font class="layui-btn" size=6 face="楷体">账户列表页面</font>
</div>
</div>
</blockquote>
<thead>
<tr>
<th>ID</th>
<th>账户</th>
<th>操作</th>
</tr>
</thead>
<tbody id ="tbody">
</tbody>
</fieldset>
</table>
<br />
<div class="page-right"></div>
<script src="${pageContext.request.contextPath}/js/table.js" type="text/javascript"></script>
</div>
</div>
<script src="${pageContext.request.contextPath}/layui/layui.js" type="text/javascript"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.basictable.min.js"></script>
<form id="delFormId" action="" method="POST">
<input type="hidden" name="_method" value="DELETE">
</form>
<form id="updFormId" action="" method="POST">
<input type="hidden" name="_method" value="PUT">
</form>
</body>
</html>
4.Page.js
function table() {
var pageNum = $("#pageNum").val();
var nowPage = $("#nowPage").val();
var countPage = $("#countPage").val();
$('.page-right').html('');
var pringString = "";
pringString += "<ul id='pagination-flickr'>";
if (nowPage <= 1) {
pringString += "<li class='previous-off'><a href='javascript:;'>首页</a></li>";
pringString += "<li class='previous-off'><a href='javascript:;'>«上一页</a></li>";
} else {
var now = parseInt(nowPage);
pringString += "<li class='previous-off'><a href='javascript:;' οnclick='first(1)'>首页</a></li>";
pringString += "<li class='previous-off'><a href='javascript:;' οnclick='pre("+ (now - 1) + ")'>«上一页</a></li>";
}
var count = parseInt(countPage);
var pArr = pageNum.split(',');
for ( var i in pArr) {
if (nowPage == i) {
pringString += "<li class='active'>" + i + "</li>";
} else if (i > 0 && i <= count) {
pringString += "<li><a href='javascript:;' οnclick='oncl(" + i+ ")' id='sum' >" + i + "</a></li>";
}
}
if (nowPage > count - 1) {
pringString += "<li class='next'><a href='javascript:;'>下一页 »</a></li>";
pringString += "<li class='next'><a href='javascript:;'>尾页</a></li>";
} else {
var now = parseInt(nowPage);
pringString += "<li class='next'><a href='javascript:;' οnclick='next("+ (now + 1) + ")' >下一页</a></li>";
pringString += "<li class='next'><a href='javascript:;' οnclick='last("+ (count) + ")'>尾页</a></li>";
}
pringString += "</ul>";
pringString +="<span><li class='next'>总页数 "+countPage+"</li></span>"
$('.page-right').append(pringString);
}
function next(nowPage) {
var u = url + "/" + nowPage;
post(u);
}
function pre(nowPage) {
var u = url + "/" + nowPage;
post(u);
}
function first(nowPage) {
var u = url + "/" + nowPage;
post(u);
}
function last(nowPage) {
var u = url + "/" + nowPage;
post(u);
}
function oncl(nowPage) {
var u = url + "/" + nowPage;
post(u);
}
function post(u) {
$.ajax({
type: "POST",
contentType : "application/json",
dataType: "json",
url: u,
success: function (data) {
$("#tbody").html('');
dis(data);
}
});
}
用Ajax使用字典
(Jquery+json的二级联动)(可拼接下拉框,复选框)
1.在java中的使用
package com.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.entry.Book;
import com.entry.BookType;
import com.entry.DamageLevel;
import com.entry.Press;
import com.entry.Role;
import com.interfac.DictionaryService;
/**
* 字典Controller
* @作者 罗玲红
*
* @时间 2017年3月29日 上午11:22:52
* https://my.oschina.net/u/780884/blog/223595
* http://www.cnblogs.com/zlay0701/p/5919841.html
* http://m.blog.csdn.net/article/details?id=52537120 (spring传递json格式的数据)
*/
@Controller
@RequestMapping(value="/dictionary")
public class DictionaryController {
@Autowired
private DictionaryService dictionaryServiceImpl;
@RequestMapping(value="/getName",method=RequestMethod.POST)
@ResponseBody
public List<BookType> getName(){
List<BookType> list=dictionaryServiceImpl.getListByPid();
return list;
}
@RequestMapping(value="/getList",method=RequestMethod.POST)
@ResponseBody
public List<BookType> getListBookName(Integer id){
List<BookType> list=dictionaryServiceImpl.getListById(id);
return list;
}
}
2.在页面的使用
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<head>
<title>字典列表页面</title>
<script src="${pageContext.request.contextPath}/js/jquery-2.1.1.min.js"></script>
</head>
<script type="text/javascript">
//图书类型的列表
$(function initProvinces() {
$('#bookType').empty();
$('#bookType').append("<option>请选择书的类型</option>");
$.ajax({
type : "POST",
dataType : "json",
url :"${pageContext.request.contextPath}/dictionary/getName",
success : function(data) {
$.each(data, function(i,list) {
$('#bookType').append("<option value='" + list.id +"'>" + list.name + "</option>"+"<br>")
});
}
});
});
$(function(){
$('#bookType').on("change",function(){
var pid = $(this).val();
initCities(pid) //图书类下面的图书
})
})
function initCities(pid) {
$('#bookName').empty();
$.ajax({
type : "POST",
dataType : "json",
url : "${pageContext.request.contextPath}/dictionary/getList",
data:{"id":pid},
success : function(data) {
$.each(data, function(i, list) {
$("<option value='"+list.id +"'>"+ list.name +"</option><br>").appendTo($('#bookName'));
});
}
});
}
</script>
<body>
添加图书:
<select id='bookType' style="width:125px">
<option>请选择书的类型</option>
</select>
<select id='bookName' style="width:125px">
<option>请选择书的名称</option>
</select>
</body>
</html>
Spring-security安全框架
1.实现权限管理所需要的jar包:
2.web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- 解决post请求中文乱码 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 允许 将post请求转为delete,put请求方式 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<!-- 配置spring的分发器 -->
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化加载配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring Security 权限框架 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--处理拦截器拦截的静态资源 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/css/*</url-pattern>
<url-pattern>/data/*</url-pattern>
<url-pattern>/js/*</url-pattern>
<url-pattern>/plugins/*</url-pattern>
<url-pattern>/images/*</url-pattern>
<url-pattern>/layui/*</url-pattern>
<url-pattern>/assets/*</url-pattern>
</servlet-mapping>
</web-app>
3.创建登录验证过滤器
包括两个类:
package com.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
/**
* 处理管理人员登陆日志
* @作者 罗玲红
*
* @时间 2017年4月10日 上午10:10:09
*/
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request,HttpServletResponse response,
Authentication authentication) throws IOException,ServletException {
UserDetails userDetails = (UserDetails)authentication.getPrincipal();
System.out.println("管理员 " + userDetails.getUsername() + " 登录");
request.getSession().setAttribute("account",userDetails.getUsername()); //因为本项目用了aop记录日志,所以就在此将session重新设置进去
super.onAuthenticationSuccess(request, response, authentication);
}
}
package com.security;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* 权限过滤
* @作者 罗玲红
* http://hotstrong.iteye.com/blog/1160153
* @时间 2017年4月10日 上午10:10:49
*/
public class LoginUsernamePasswordAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {
}
4.spring-security.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http >
<!-- 不拦截login.jsp -->
<intercept-url pattern="/views/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!--仅拦截到manager下面的内容,具备access对应权限的-->
<intercept-url pattern="/**"/>
<!-- 设置登录过滤器 -->
<custom-filter before="FORM_LOGIN_FILTER" ref="authenticationProcessingFilter" />
<!-- 登录表单设置 -->
<form-login login-page="/views/login"
default-target-url="/views/main"
authentication-failure-url="/views/login" />
<!-- 登出操作后跳转到该页面 -->
<logout logout-success-url="/views/loggedout"
delete-cookies="JSESSIONID" />
<remember-me />
<!-- SESSION超时后跳转到该页面 -->
<session-management invalid-session-url="/views/timeout">
</session-management>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<!-- 直接使用SQL语句查询登录帐号对应权限,
users-by-username-query:查询登录用户是否存在
authorities-by-username-query:查询登录用户权限(登录用户可以不属于任何组,从power表中获取权限)
group-authorities-by-username-query:查询登录用户所在组的权限
-->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select a.account,a.`password`,true from account as a where a.account = ?"
authorities-by-username-query="select a.account,p.`name` from account as a LEFT OUTER JOIN roleaccount as ra on (a.id=ra.accountId)
LEFT OUTER JOIN role as r on (r.`code`=ra.roleId ) LEFT OUTER JOIN rolepower as rp on (rp.roleCode=r.`code`)
LEFT OUTER JOIN power as p on (rp.powerId=p.id ) where a.account = ?" />
</authentication-provider>
</authentication-manager>
<!-- 自定义消息 -->
<b:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<b:property name="basename"
value="classpath:org/springframework/security/messages" />
</b:bean>
<!-- 定制登录过滤器 -->
<beans:bean id="loginSuccessHandler" class="com.security.LoginSuccessHandler">
<b:property name="defaultTargetUrl">
<!-- 登录成功后转发到该页面 -->
<b:value>/views/main</b:value>
</b:property>
</beans:bean>
<beans:bean id="authenticationProcessingFilter" class="com.security.LoginUsernamePasswordAuthenticationFilter">
<beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"></beans:property>
<beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler"></beans:property>
<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
</beans:bean>
<beans:bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl">
<!-- 登录失败后转发到该页面 -->
<beans:value>/views/login</beans:value>
</beans:property>
</beans:bean>
<!-- 自定义拦截器 -->
</beans:beans>
5.页面使用
导入标签:
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%>
<security:authorize ifAnyGranted="ROLE_ADMIN,ROLE_BOOK_SELECT">
<a class="waves-effect" href="javascript:Tab.addTab('图书管理', '${pageContext.request.contextPath}/views/book/list');">图书管理</a>
</security:authorize>
Springmvc Spring Mybatis Maven 项目管理
2.pom.xml
注意:当导入的jar比eclipse自带的版本低的时候会报错,mybatis-spring的版本要1.3.0
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.mybatis</groupId>
<artifactId>firstMybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>firstMybatis Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<!-- spring版本号 -->
<spring.version>4.3.5.RELEASE</spring.version>
<!-- mybatis版本号 -->
<mybatis.version>3.4.1</mybatis.version>
<!-- slf4j版本 -->
<slf4j.version>1.7.7</slf4j.version>
<!-- log4j日志文件管理包版本 -->
<log4j.version>1.2.17</log4j.version>
<!-- springsecurity 版本号 -->
<org.springframework.security.version>3.2.9.RELEASE</org.springframework.security.version>
<!-- jackson版本 -->
<com.fasterxml.jackson.version>2.8.2</com.fasterxml.jackson.version>
<!-- junit测试版本 -->
<junit.version>4.10</junit.version>
<!-- c3p0版本号 -->
<com.mchange>0.9.2.1</com.mchange>
<!-- mybatis-spring 版本 -->
<org.mybatis.spring>1.3.0</org.mybatis.spring>
<!-- mysql链接包 -->
<mysql.connector>5.1.39</mysql.connector>
</properties>
<dependencies>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${com.mchange}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${org.springframework.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis/spring包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${org.mybatis.spring}</version>
</dependency>
<!-- 导入java ee jar 包 -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
<!-- 导入Mysql数据库链接jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector}</version>
</dependency>
<!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<!-- JSTL标签类 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 格式化对象,方便输出日志 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.41</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<!-- 上传组件包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson.version}</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<!--Log4j2配置 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.5</version>
</dependency>
<!--解决Spring使用slf4j输出日志与log4j冲突的问题 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.13</version>
</dependency>
</dependencies>
<build>
<finalName>library</finalName>
</build>
</project>
3.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- 解决Post请求中文乱码问题 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 使得支持 GET POST PUT DELETE 请求 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- springSecurity权限控制框架的配置 -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring的配置 -->
<servlet>
<!-- 配置springmvc的分发器 -->
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化加载spring的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
spring框架的启动入口 ContextLoaderListener 2 作用:在启动Web 容器时,自动装配Spring applicationContext.xml 的配置信息,所有有时候报错是因为没有配置applicationContext.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener </listener-class>
</listener>
4.配置applicationContext-dataSource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:property-placeholder location="classpath:db.properties" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
</beans>
5.配置applicationContext-springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<!-- 如果需要用<mvc:view-controller>,那么一定要加上<mvc:annotation-driven />,否则除<mvc:view-controller>配置有效外,其他的url都为404 -->
<mvc:view-controller path="/login" view-name="login" />
<mvc:view-controller path="/main" view-name="main" />
<mvc:view-controller path="/loggedout" view-name="loggedout" />
<mvc:view-controller path="/timeout" view-name="timeout" />
<bean id="multipartResolver"
class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</bean>
<!-- 配置springmvc的视图渲染器 -->
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 配置项目中需要的jackson bean -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
p:ignoreDefaultModelOnRedirect="true">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
</beans>
6.配置applicationContext-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<import resource="applicationContext-dataSource.xml" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/mapper/*.xml"></property>
<!-- 类型命名 -->
<property name="typeAliasesPackage" value="com.entry" />
</bean>
<!-- 配置mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描对应的接口的路径,如果需要扫描多个包中间用半角逗号隔开 -->
<property name="basePackage" value="com.interDao"></property>
</bean>
</beans>
7.配置applicationContext-tx.xml
为了让大家看的更加清楚,这里我使用了两种事务配置方式,在项目中一般使用一种事务配置方式(注解方式,xml配置方式,推荐使用xml配置方式)
事务一般都在service中使用,所以aop记录日志都切至service层
1,全注解方式 applicationContext-tx.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 引入是为了去消黄色警告-->
<import resource="applicationContext-mybatis.xml" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 需要配置注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager" order="3" />
</beans>
8.配置applicationContext-aop.xml
aop这里事务的配置方式的是xml配置方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:component-scan base-package="com"></context:component-scan>
<import resource="applicationContext-mybatis.xml" />
<import resource="applicationContext-tx.xml" />
<aop:config>
<!-- 配置aop切点 -->
<aop:pointcut expression="execution(* com.service.*.*(..))" id="log" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="log" order="2" />
<aop:aspect id="log" ref="aopLogHandler" order="1">
<aop:before method="before" pointcut-ref="log" />
<aop:after-returning method="returning" pointcut-ref="log" />
<aop:after-throwing method="throwing" pointcut-ref="log" throwing="e" />
</aop:aspect>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="return*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="throw*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
</beans>
注意看这两个配置文件中红色标记处,这是设置优先级,用以保证事务回滚时,aop中的数据不会回滚
9.配置 applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<http pattern="/getCodeImgServlet" security="none"/>
<http>
<!-- 不拦截login.jsp -->
<intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!--仅拦截到manager下面的内容,具备access对应权限的 -->
<intercept-url pattern="/com/**" />
<!-- 设置登录过滤器 -->
<custom-filter before="FORM_LOGIN_FILTER" ref="authenticationProcessingFilter" />
<!-- 登录表单设置 -->
<form-login login-page="/login" default-target-url="/main" authentication-failure-url="/login" />
<!-- 登出操作后跳转到该页面 -->
<logout logout-success-url="/loggedout" delete-cookies="JSESSIONID" />
<remember-me />
<!-- SESSION超时后跳转到该页面 -->
<session-management invalid-session-url="/timeout"></session-management>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<!-- 直接使用SQL语句查询登录帐号对应权限, users-by-username-query:查询登录用户是否存在 authorities-by-username-query:查询登录用户权限(登录用户可以不属于任何组,从t_user_role表中获取权限)
group-authorities-by-username-query:查询登录用户所在组的权限 -->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT ACC.ACCOUNT ,ACC.`PASSWORD`,true FROM ACCOUNT AS ACC WHERE ACC.account= ?"
authorities-by-username-query="SELECT A.account,P.`name` FROM ACCOUNT AS A
LEFT OUTER JOIN ROLEACCOUNT AS RA ON (A.id = RA.accountId)
LEFT OUTER JOIN ROLE AS R ON (R.id = RA.roleId)
LEFT OUTER JOIN ROLEPOWERS AS RP ON (RP.roleId = R.id)
LEFT OUTER JOIN POWERS AS P ON (P.id = RP.powersId)
WHERE A.account = ?" />
</authentication-provider>
</authentication-manager>
<!-- 自定义消息 -->
<b:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<b:property name="basename"
value="classpath:org/springframework/security/messages" />
</b:bean>
<!-- 定制登录过滤器 -->
<beans:bean id="loginSuccessHandler" class="com.security.LoginSuccessHandler">
<b:property name="defaultTargetUrl">
<!-- 登录成功后转发到该页面 -->
<b:value>/main</b:value>
</b:property>
</beans:bean>
<beans:bean id="authenticationProcessingFilter" class="com.security.LoginUsernamePasswordAuthenticationFilter">
<beans:property name="authenticationSuccessHandler" ref="loginSuccessHandler"></beans:property>
<beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler"></beans:property>
<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
</beans:bean>
<beans:bean id="authenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl">
<!-- 登录失败后转发到该页面 -->
<beans:value>/login</beans:value>
</beans:property>
</beans:bean>
</beans:beans>
10.讲述一下springSecurity权限框架的简单使用
上面 applicationContext-security.xml中有两个自定义类
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
@Override
@Loggable(describe = "登陆验证", module = LogModule.ACCOUNT, optType = LogOptType.SELECT)
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
UserDetails userDetails = (UserDetails)authentication.getPrincipal();
//输出登录提示信息,得到用户名: userDetails.getUsername()
System.out.println("管理员 " + userDetails.getUsername() + " 登录");
request.getSession().setAttribute("account",userDetails.getUsername());
super.onAuthenticationSuccess(request, response, authentication);
}
}
public class LoginUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
//这里是用作验证码的验证的,重写attemptAuthentication()方法,这里不做详细介绍
}
首先这里的login.jsp将会有些不同,主要体现在form表单
<form id="form" action="<%=request.getContextPath() %>/j_spring_security_check" method="POST">
<input type="text" id="account" name="j_username" class="form-control" placeholder="帐号">
<input type="password" id="password" name="j_password" class="form-control" placeholder="密码">
<input type="submit" value="登陆" />
</form>
登陆以后在jsp中可以控制div的显示
如下面一段代码
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%>
<security:authorize ifAnyGranted='ROLE_ADMIN,ROLE_ACCOUNT_SELECT'>
<li><a class="waves-effect"
href="javascript:Tab.addTab('账号管理', '${pageContext.request.contextPath}/sys/account/list');">账号管理
</a></li>
</security:authorize>
ifAnyGranted='ROLE_ADMIN,ROLE_ACCOUNT_SELECT'
表示拥有ROLE_ADMIN 或者 拥有 ROLE_ACCOUNT_SELECT 权限的用户才能看到该内容的显示 (用or不行)
ifAnyGranted='ROLE_ADMIN and ROLE_ACCOUNT_SELECT'
表示ROLE_ADMIN 和 拥有 ROLE_ACCOUNT_SELECT 权限的用户才能看到该内容的显示
11.ssm 整合ehcache缓存
若要整合ehcache 缓存需要引入jar
<!-- 整合ehcache缓存机制所需要的jar -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.0.1</version>
</dependency>
在spring 配置文件中配置ehcache 的bean
<!-- 配置ehcache缓存Bean -->
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:applicationContext-ehcache.xml" />
</bean>
编写application-ehcache.xml缓存配置
描述:
<!-- maxElementsInMemory:缓存中最大允许创建的对象数 。maxInMemory:设定内存中创建对象的最大值。
eternal:设置元素(译注:内存中对象)是否永久驻留。如果是,将忽略超时限制且元素永不消亡。
timeToIdleSeconds:设置某个元素消亡前的停顿时间。 timeToLiveSeconds:为元素设置消亡前的生存时间.
overflowToDisk:设置当内存中缓存达到maxInMemor限制时元素是否可写到磁盘上。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。
你可以设置为FIFO(先进先出)或是LFU(较少使用)。 diskPersistent:重启时内存不持久化到硬盘。 -->
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="java.io.tmpdir" />
<defaultCache
maxElementsInMemory="10000"
memoryStoreEvictionPolicy="LRU"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="300"
overflowToDisk="false"
diskPersistent="false" />
<cache
name="districtDataCache"
maxElementsInMemory="4000"
eternal="true"
overflowToDisk="false"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
在mapper.xml中配置ehcache缓存
<cache readOnly="true">
<property name="timeToIdleSeconds" value="3600" />
<property name="timeToLiveSeconds" value="3600" />
<property name="maxEntriesLocalHeap" value="1000" />
<property name="maxEntriesLocalDisk" value="10000000" />
<property name="memoryStoreEvictionPolicy" value="LRU" />
</cache>
12.一个account模块的例子
1.accountMapper.xml
下面是一个mapper.xml -- accountMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.interDao.AccountMapper">
<!-- 得到分页数据 -->
<select id="getList" resultMap="accountResultMap">
select * from account where 1 = 1 limit #{startIndex},#{endIndex}
</select>
<!-- 得到数据总条数 -->
<select id="getTotal" resultType="java.lang.Integer">
select count(*) from account
</select>
<delete id="del">
delete from account where id = #{id}
</delete>
<update id="upd" parameterType="Account">
<![CDATA[
update account set account = #{account} , `password` = #{password} where id = #{id}
]]>
</update>
<!-- 添加一条记录,并返回主键 -->
<insert id="add" parameterType="Account" useGeneratedKeys="true" keyProperty="id">
<![CDATA[
insert into account(account,password) values (#{account},#{password})
]]>
</insert>
<!-- 修改回显 -->
<select id="each" resultMap="accountResultMap">
select * from account where id = #{value}
</select>
<!-- 批量插入,一个账户对应多个角色 -->
<insert id="addRoleAcc">
<selectKey order="AFTER" keyProperty="id" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
insert into roleAccount values
<foreach collection="role" item="roleName" separator=",">
(
#{accId},#{roleName}
)
</foreach>
</insert>
<resultMap type="Account" id="accountResultMap">
<result property="id" column="id" />
<result property="account" column="account" />
<result property="password" column="password" />
</resultMap>
</mapper>
2.interface AccountMapper.java
com.interDao.AccountMapper.java
package com.interDao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.entry.Account;
public interface AccountMapper {
/**
* 查询ACCOUNT中的分页数据
*
* @param nowPage
* 当前页
* @param pageSize
* 每页显示多少条
* @return
*/
public List<Account> getList(@Param(value = "startIndex") Integer startIndex,
@Param(value = "endIndex") Integer endIndex);
/**
* 得到account表总条数
*
* @return total 数据总条数
*/
public Integer getTotal();
/**
* 添加ACCOUNT中的数据
*
* @param acc
* Account
* @return 返回影响行数
*/
public int add(Account acc);
/**
* 根据id删除数据
*
* @param id
* @return 影响行数
*/
public int del(Integer id);
/**
* 修改
*
* @param acc
* Account
* @return 影响行数
*/
public int upd(Account acc);
/**
* 给账户分配角色
*
* @param accId
* 账户id
* @param list
* 角色id 集合
* @return 影响行数
*/
public int addRoleAcc(@Param(value = "accId") Integer accId, @Param(value = "role") List<String> list);
/**
* 信息修改回显示
*
* @param id
* 账户id
* @return Account
*/
public Account each(Integer id);
}
3.AccountController.java
下面贴出 controller 与 service 的代码
@Controller
@RequestMapping("/com/sys/account/")
public class AccountController {
@Autowired
private AccountService accountServiceImpl;
/**
* 账户添加
*
* @param acc Account
* @param bindResult 使用了jsr303
* @param model Model
* @return
*/
@RequestMapping("add")
public String add(@Valid Account acc, BindingResult bindResult, Model model) {
try {
if (bindResult.getErrorCount() > 0)
model.addAttribute(Status.MESSAGE, Status.RESPONSE_ADDFAIL);
else {
boolean bool = accountServiceImpl.add(acc);
if (!bool)
model.addAttribute(Status.MESSAGE, Status.RESPONSE_ADDFAIL);
}
} catch (Exception e) {
e.printStackTrace();
}
return "sys/account/list";
}
/**
* 账户删除
*
* @param model Model
* @param id 主键
* @return
*/
@RequestMapping(value = { "del/{id}" }, method = RequestMethod.DELETE)
public String del(Model model, @PathVariable("id") Integer id) {
try {
boolean bool = accountServiceImpl.del(id);
if (!bool)
model.addAttribute(Status.MESSAGE, Status.RESPONSE_DELFAIL);
} catch (Exception e) {
e.printStackTrace();
}
return "sys/account/list";
}
/**
* 账户修改
*
* @param acc Account
* @param bindResult
* @param model
* @return
*/
@RequestMapping(value = { "update" }, method = RequestMethod.POST)
public String update(@Valid Account acc, BindingResult bindResult, Model model) {
try {
if (bindResult.getErrorCount() > 0)
model.addAttribute(Status.MESSAGE, Status.RESPONSE_UPDFAIL);
else {
boolean bool = accountServiceImpl.update(acc);
if (!bool)
model.addAttribute(Status.MESSAGE, Status.RESPONSE_UPDFAIL);
}
} catch (Exception e) {
e.printStackTrace();
}
return "sys/account/list";
}
/**
* 得到修改回显的数据
*
* @param model
* @param id
* 主键
* @return
*/
@RequestMapping(value = { "echo/{id}" }, method = RequestMethod.PUT)
public String echo(Model model, @PathVariable("id") Integer id) {
Account acc = accountServiceImpl.echo(id);
model.addAttribute("acc", acc);
return "sys/account/update";
}
/**
* 得到列表分页数据
*
* @param nowPage
* 当前页
* @return
*/
@RequestMapping(value = { "list/{nowPage}" }, method = RequestMethod.POST)
@ResponseBody
public Page<Account> json(@PathVariable("nowPage") Integer nowPage) {
Page<Account> page = accountServiceImpl.getList(nowPage, 7);
return page;
}
}
4.interface AccountService.java
下面贴出接口 AccountService.java
package com.interfac;
import com.entry.Account;
import com.entry.Page;
/**
*
* @author 肖亮亮
*
* @date 2017年4月4日 上午10:19:39
*/
public interface AccountService {
/**
* 查询ACCOUNT中的分页数据
*
* @param nowPage
* 当前页
* @param pageSize
* 每页显示多少条
* @return
*/
public Page<Account> getList(int nowPage, int pageSize);
/**
* 根据id删除ACCOUNT中的数据
*
* @param id
* 表主键
* @return true 删除成功 , false 删除失败
*/
public boolean del(int id);
/**
* 修改ACCOUNT中的数据
*
* @param acc
* Account
* @return true 修改成功, false 修改失败
*/
public boolean update(Account acc);
/**
* 添加ACCOUNT中的数据
*
* @param acc
* Account
* @return true 添加成功, false 添加失败
*/
public boolean add(Account acc);
/**
* 账户修改信息回显,根据id
*
* @param id
* 表主键
* @return true 成功, false 失败
*/
public Account echo(int id);
/**
* 向角色账户关系表中插入数据
*
* @param acc
* Account
* @param key
* 添加时返回的主键
* @return
*/
public boolean insertRoleAccount(Account acc, int key);
}
5.AccountServiceImpl.java
下面贴出业务逻辑层实现类 AccountServiceImpl.java
/**
*
* @author 肖亮亮
*
* @date 2017年3月28日 下午3:36:24
*/
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
/**
* 查询ACCOUNT中的分页数据
*
* @param nowPage
* 当前页
* @param pageSize
* 每页显示多少条
* @return
*/
@Override
@Loggable(describe = "查询ACCOUNT中的分页数据", module = LogModule.ACCOUNT, optType = LogOptType.SELECT)
public Page<Account> getList(int nowPage, int pageSize) {
Page<Account> page = new Page<>(nowPage, pageSize, accountMapper.getTotal());
List<Account> rows = accountMapper.getList(page.getStartIndex(), page.getEndIndex());
page.setRows(rows);
return page;
}
/**
* 根据id删除ACCOUNT中的数据
*
* @param id
* 表主键
* @return true 删除成功 , false 删除失败
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
@Loggable(describe = "根据id删除ACCOUNT中的数据", module = LogModule.ACCOUNT, optType = LogOptType.DELETE)
public boolean del(int id) {
int sum = accountMapper.del(id);
return (sum == 1 ? true : false);
}
/**
* 修改ACCOUNT中的数据
*
* @param acc
* Account
* @return true 修改成功, false 修改失败
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
@Loggable(describe = "修改ACCOUNT中的数据", module = LogModule.ACCOUNT, optType = LogOptType.UPDATE)
public boolean update(Account acc) {
int sum = accountMapper.upd(acc);
return (sum == 1 ? true : false);
}
/**
* 添加ACCOUNT中的数据
*
* @param acc
* Account
* @return true 添加成功, false 添加失败
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
@Loggable(describe = "插入数据到ACCOUNT中", module = LogModule.ACCOUNT, optType = LogOptType.INSERT)
public boolean add(Account acc) {
boolean is = false;
// 向Account表中插入数据
accountMapper.add(acc);
int key = acc.getId();
// 向关系表roleAccount中插入数据
is = insertRoleAccount(acc, key);
return is;
}
/**
* 账户修改信息回显,根据id
*
* @param id
* 表主键
* @return true 成功, false 失败
*/
@Override
@Loggable(describe = "账户修改信息回显,根据id", module = LogModule.ACCOUNT, optType = LogOptType.SELECT)
public Account echo(int id) {
Account acc = accountMapper.each(id);
return acc;
}
/**
* 向角色账户关系表中插入数据
*
* @param acc
* Account
* @param key
* 添加时返回的主键
* @return true 添加成功 , false 添加失败
*/
@Override
@Loggable(describe = "向关系表roleAccount中插入数据", module = LogModule.ROLE_ACCOUNT, optType = LogOptType.INSERT)
public boolean insertRoleAccount(Account acc, int key) {
String strArr[] = acc.getRole().split(",");
List<String> list = Arrays.asList(strArr);
int sum = accountMapper.addRoleAcc(acc.getId(), list);
return (sum >= 1 ? true : false);
}
}
6.Page.java
package com.entry;
import java.util.ArrayList;
import java.util.List;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* 分页实体类
*
* @author 肖亮亮
*
* @date 2017年3月28日 上午9:08:45
*/
public class Page<T> {
// 当前页
private Integer nowPage;
// 页面要显示信息条数
private Integer pageSize = 5;
// 根据页面显示的条数计算总页数
private Integer countPage;
// 根据传入的数据库查询数据库中的信息的条数
private Integer total;
// 向数据库查询时的开始的下标
private Integer startIndex;
// 向数据库查询时的查询条数
private Integer endIndex;
// 页面页码个数
private Integer num = 5;
// 页面页码总数
private String pageNum;
// 将查询到的数据存放到这里
private List<T> rows = new ArrayList<>();
/**
* 传入总记录数 和当前页
*
* @param total
* 总记录数
* @param nowPage
* 当前页
*/
public Page(Integer nowPage, String tableName, Integer pageSize, JdbcTemplate jdbcTemplate) {
String sql = "SELECT COUNT(*) FROM " + tableName;
// 一共有多少条数据
this.total = jdbcTemplate.queryForObject(sql, Integer.class);
getData(nowPage, pageSize);
}
private void getData(Integer nowPage, Integer pageSize) {
// 每页显示多少条
this.pageSize = pageSize;
// 赋值
this.nowPage = nowPage;
// 判断当前页是否合法
if (this.nowPage < 1) {
this.nowPage = 1;
}
// 计算总页数
this.countPage = this.total % this.pageSize == 0 ? this.total / this.pageSize : this.total / this.pageSize + 1;
if (this.nowPage > this.countPage) {
this.nowPage = this.countPage;
}
// 计算出开始的记录下标,和每页要显示的条数
if (this.nowPage == 0) {
this.startIndex = this.nowPage * this.pageSize;
this.endIndex = this.pageSize;
} else {
this.startIndex = (this.nowPage - 1) * this.pageSize;
this.endIndex = this.pageSize;
}
this.pageNum = getPageNums();
}
public Page(Integer nowPage, Integer pageSize, Integer total) {
this.total = total;
getData(nowPage, pageSize);
}
/**
* pageCount 总页数 pageCurr 当前页 num 显示的页码数
*
* @return
*/
private String getPageNums() {
StringBuffer sb = new StringBuffer();
if (num >= countPage) {
for (int i = 1; i <= countPage; i++) {
sb.append(i).append(",");
}
} else if (nowPage == countPage) {
for (int i = countPage - num + 1; i <= countPage; i++) {
if (i > countPage) {
break;
}
sb.append(i).append(",");
}
} else if (nowPage + num > countPage) {
for (int i = countPage - num; i < countPage; i++) {
if (i > countPage) {
break;
}
sb.append(i).append(",");
}
} else {
for (int i = nowPage; i < nowPage + num; i++) {
if (i > countPage) {
break;
}
sb.append(i).append(",");
}
}
return sb.toString();
}
public String getPageNum() {
return pageNum;
}
public void setPageNum(String pageNum) {
this.pageNum = pageNum;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public Integer getStartIndex() {
return startIndex;
}
public Integer getEndIndex() {
return endIndex;
}
public Integer getTotal() {
return total;
}
public Integer getNowPage() {
return nowPage;
}
public void setNowPage(Integer nowPage) {
this.nowPage = nowPage;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getCountPage() {
return countPage;
}
public void setCountPage(Integer countPage) {
this.countPage = countPage;
}
public void setTotal(Integer total) {
this.total = total;
}
public void setStartIndex(Integer startIndex) {
this.startIndex = startIndex;
}
public void setEndIndex(Integer endIndex) {
this.endIndex = endIndex;
}
}
7.Page.js
function table() {
var pageNum = $("#pageNum").val();
var nowPage = $("#nowPage").val();
var countPage = $("#countPage").val();
$('.page-right').html('');
var pringString = "";
pringString += "<ul id='pagination-flickr'>";
if (nowPage <= 1) {
pringString += "<li class='previous-off'><a href='javascript:;'>首页</a></li>";
pringString += "<li class='previous-off'><a href='javascript:;'>«上一页</a></li>";
} else {
var now = parseInt(nowPage);
pringString += "<li class='previous-off'><a href='javascript:;' οnclick='oncl(1)'>首页</a></li>";
pringString += "<li class='previous-off'><a href='javascript:;' οnclick='oncl("+ (now - 1) + ")'>«上一页</a></li>";
}
var count = parseInt(countPage);
var pArr = pageNum.split(',');
for ( var i in pArr) {
if (nowPage == i) {
pringString += "<li class='active'>" + i + "</li>";
} else if (i > 0 && i <= count) {
pringString += "<li><a href='javascript:;' οnclick='oncl(" + i+ ")' id='sum' >" + i + "</a></li>";
}
}
if (nowPage > count - 1) {
pringString += "<li class='next'><a href='javascript:;'>下一页 »</a></li>";
pringString += "<li class='next'><a href='javascript:;'>尾页</a></li>";
} else {
var now = parseInt(nowPage);
pringString += "<li class='next'><a href='javascript:;' οnclick='oncl("+ (now + 1) + ")' >下一页</a></li>";
pringString += "<li class='next'><a href='javascript:;' οnclick='oncl("+ (count) + ")'>尾页</a></li>";
}
pringString += "</ul>";
pringString +="<span><li class='next'>总页数 "+countPage+"</li></span>"
$('.page-right').append(pringString);
}
function oncl(nowPage) {
$('#nowPage').val(nowPage);
get();
}