1 配置文件 security-ns.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:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> //需要过滤不被拦截的请求 <security:http pattern="/openapi/**" security="none" /> <security:http pattern="/useraccounts/userprofile.json" security="none" /> <security:http pattern="/useraccounts/register**" security="none" /> //entry-point-ref 配置自定义登录 <security:http auto-config="false" entry-point-ref="authenticationEntryPoint"> <security:intercept-url pattern="/backManage/**" access="ROLE_BACK_USER" /> <security:intercept-url pattern="/mall/**" access="ROLE_BACK_USER" /> <security:intercept-url pattern="/thirdUser/**" access="ROLE_USER" /> <security:intercept-url pattern="/useraccounts/**" access="ROLE_USER" /> <security:intercept-url pattern="/cart/**.html" access="ROLE_USER" /> <security:intercept-url pattern="/ticket/**" access="ROLE_USER,ROLE_BACK_USER" /> <security:intercept-url pattern="/order/**" access="ROLE_USER" /> <security:intercept-url pattern="/comment/**" access="ROLE_USER" /> <security:intercept-url pattern="/personal/**" access="ROLE_USER" /> <security:intercept-url pattern="/favorite/**" access="ROLE_USER" /> //需要替换的Filter顺序,配置自定义custom-filter时必须蔣auto-config="false",不然会报已经存在同样的过滤器错误 <security:custom-filter ref="myLoginFilter" position="FORM_LOGIN_FILTER" /> //登出配置 <security:logout logout-success-url="${local.service.url}"/> </security:http> //密码加密工具类 <bean id="encoder" /> //认证管理器 <security:authentication-manager alias="authenticationManager"> //UserDetailsService实现 主要用于用户的查询 <security:authentication-provider user-service-ref="userLoginService"> <security:password-encoder ref="encoder"> </security:password-encoder> </security:authentication-provider> </security:authentication-manager> <bean id="myLoginFilter" > <property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationFailureHandler" ref="failureHandler"/> <property name="authenticationSuccessHandler" ref="successHandler"/> </bean> //成功登录后 <bean id="successHandler" > <property name="defaultTargetUrl" value="${local.service.url}"/> </bean> //登录失败 <bean id="failureHandler" > <property name="defaultFailureUrl" value="${local.service.url}/login.html?validated=false"/> </bean> <bean id="authenticationEntryPoint" > <property name="loginFormUrl" value="${local.service.url}/login.html" /> </bean> </beans> 2 UserLoginServiceImpl 查询用户实现类 @Named("userLoginService") public class UserLoginServiceImpl implements UserDetailsService ,LoginService{ @Inject private UserLoginDAO userLoginDAO; @Override public WrappedUserLogin getUserLogin() { try { WrappedUserLogin wrappedUserLogin = (WrappedUserLogin) SecurityContextHolder .getContext().getAuthentication().getPrincipal(); return wrappedUserLogin; } catch (Exception e) { return null; } } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("用户名-------------"+username); UserLogin userLogin = null; if(username != null && !"".equals(username)&& username.indexOf("@") > 0){ userLogin = userLoginDAO.findByEmail(username); username = userLogin.getNick(); }else{ userLogin = userLoginDAO.findByNick(username); } System.out.println("user is null ---"+userLogin.getUserType()); String nick = userLogin.getNick(); String email = userLogin.getEmail(); String mobile = userLogin.getMobile(); int userType = userLogin.getUserType(); List<GrantedAuthority> resultAuths = new ArrayList<GrantedAuthority>(); // 前台用户 if (userType == 1) { resultAuths.add(new SimpleGrantedAuthority("ROLE_USER")); } else { resultAuths.add(new SimpleGrantedAuthority("ROLE_BACK_USER")); } return new WrappedUserLogin(userLogin.getId(), email, nick, mobile, userLogin.getPassword(), userType,resultAuths); } } 3 重写用户名密码验证 public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{ //用户名 public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username"; //密码 public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password"; //需要回调的URL 自定义参数 public static final String SPRING_SECURITY_FORM_REDERICT_KEY = "spring-security-redirect"; /** * @deprecated If you want to retain the username, cache it in a customized {@code AuthenticationFailureHandler} */ @Deprecated public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME"; private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY; private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY; private String redirectParameter = SPRING_SECURITY_FORM_REDERICT_KEY; private boolean postOnly = true; //~ Constructors =================================================================================================== public MyUsernamePasswordAuthenticationFilter() { super(); } //~ Methods ======================================================================================================== public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } String username = obtainUsername(request); String password = obtainPassword(request); String redirectUrl = obtainRedercitUrl(/blog_article/request/index.html); if (username == null) { username = ""; } if (password == null) { password = ""; } //自定义回调URL,若存在则放入Session if(redirectUrl != null && !"".equals(redirectUrl)){ request.getSession().setAttribute("callCustomRediretUrl", redirectUrl); } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Allow subclasses to set the "details" property setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /** * Enables subclasses to override the composition of the password, such as by including additional values * and a separator.<p>This might be used for example if a postcode/zipcode was required in addition to the * password. A delimiter such as a pipe (|) should be used to separate the password and extended value(s). The * <code>AuthenticationDao</code> will need to generate the expected password in a corresponding manner.</p> * * @param request so that request attributes can be retrieved * * @return the password that will be presented in the <code>Authentication</code> request token to the * <code>AuthenticationManager</code> */ protected String obtainPassword(HttpServletRequest request) { return request.getParameter(passwordParameter); } /** * Enables subclasses to override the composition of the username, such as by including additional values * and a separator. * * @param request so that request attributes can be retrieved * * @return the username that will be presented in the <code>Authentication</code> request token to the * <code>AuthenticationManager</code> */ protected String obtainUsername(HttpServletRequest request) { return request.getParameter(usernameParameter); } protected String obtainRedercitUrl(HttpServletRequest re
序章前言
随着时间的推移,SSH已经不再满足项目的需要,至少无法满足笔者项目的需要。时代的过渡直接决定着技术的过渡。慢慢的从N年前的SSH(Struts+Spring+Hibernare)到今天的SSJ(Spring3.x mvc + Spring3.x Core + JPA2.x),我相信大家同笔者一样感触蛮多...晚上睡觉的时候去好好回味下...
当然不是说Struts2.x或者是Hibernate不好,只是说很多时候客户需求决定项目技术的选向。不管你觉得好与不好,至少不是你说了算,而是客户说了算。对于国外的项目,老外总是喜欢尝试用一些新颖的技术,当然这也没有什么不好,毕竟SSJ相对来说也算不上什么新东西了,只是国内使用这套标准的公司并不是特别多而已。
由于本章内容仅仅只是序章,所以笔者在本章只会讲解一些涉及到后续章节的概念。那么我
们就先从Spring开始吧。不知大家是否发现,Spring已经逐渐从单纯的一种技术规范实现慢慢的蜕变为企业的一站式解决方案?是的,如今整个领域对象中几乎随处可见Spring的身影,Spring贯穿了效验层、控制层、业务层甚至是持久层...笔者接触Spring至今也有多年左右了,希望本文的一些观点不会成为某些高手所为的妙论...
其实你完全可以将Spring理解为一个载满各种高精尖武器的“航母平台”,其平台上面承载着各式各样,足以令你眼花缭乱但却实用的技术,其覆盖率之广。如果你想用mvc,Spring为你提供有支持RESTful风格的mvc Framework,或者允许与第三方mvc 产品进行无缝整合。如果你想使用Spring的核心业务,Spring最新的3.x版本将带给你全新的体验。如果你想对权限进行控制,Spring为你提供有Spring security。如果你不想手动管理你的持久层事物,Spring为你提供有各式各样的第三方ORM 产品的整合方案,甚至还为你提供有高效的Spring JDBC(Spring JDBC仅仅只是针对传统的JDBC做了轻量级封装,熟悉JDBC的开发人员上手应该是很快的,并不会觉得复杂与麻烦)。如果你是Android的开发人员,Spring照样为你提供有基于Mobile领
域的各种规范实现。当然Spring所带来的影响力同样也是巨大的,时至今日Spring更像是驱动技术市场脚步的一匹黑马,越来越多的厂商阵营,越来越多的规范性规划,都在向Spring靠拢。
听了这么多,你可能会觉得Spring就是一个威力超强的高效粘合剂,不论是Spring原生的还是第三方的,Spring都可以将其进行快速且无缝的整合,一切都显得是那么顺其自然,浑然天成。Spring的最新版本为3.x,在以往版本的基础之上,Spring大幅度的简化了开发人员的编码量,更清晰的定位了配置文件的作用以及更多的Annotations支持,使得开发Spring应用将会成为一件很美妙的事情。
注意:
在很多年前,几乎所有的开发人员都希望将可配置型代码写进配置文件中,因为这样除了可以很好的解决代码耦合的问题,同样也可以解决系统每次更改属性都要反复部署的问题。但随着时间的推移,咱们的配置文件几乎越来越庞大,文件中的内容越来越冗长,为了很好解决配置文件的瘦身问题,越来越多的开源项目又开始将配置文件中的内容移至代码中,Spring其实就是其中一个。虽然这种做法在理论上看来无非是重量级的操作,但绝非是高侵入式的,因为很多开源项目并不是直接将第三方代码侵入进咱们的业务逻辑中,而只是以Annotation的方式进行嵌入。这种侵入级别而言对于开发人员来说并不是不能接受的,并且也是某些开源项目的目标,就像.net平台一样,始终都允许只用微软的东西,说不定某些开源项目拥有技术垄断的商业嫌疑(开个玩笑)。
接下来我们简要的聊一聊JPA。JPA全称为Java Persistence API(Java持久化规范:作为JSR-220实现的一部分),它本身是内嵌至EJB3.x 中的一种规范,从理论上来说它也是属于J2EE规范的一种。但请你记住,JPA并不是产品,也不是技术,它仅仅只是一套优秀的ORM整合规范。笔者经常在论坛中听到很多开发人员喜欢拿JPA去和Hibernate或者Ibatis等成熟的ORM 产品进行比较,其实这完全是牛头不对马嘴,这根本就不是一回事。请记住了,规范并不是实现(规范仅是概念)。
JPA的出现有效的整合了ORM领域的统一,现在市面山越来越多的ORM厂商在向JPA规范靠拢,比如Hibernate JPA,Ibatis JPA等等。刚刚笔者也提到过了,JPA的最大优势是标准化
,但同样也包含另外4点优势:
1、对容器级特性的支持:JPA 框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
2、简单易用,集成方便:JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成。
3
对 web 中用什么办法固定一个表的表头,google, baidu, being 了很多,发现满意的没有,要么不能跨浏览器,要么一个单元格内容大一点就把样式撑乱了。
后来了一下ligerUI,发现它有这个功能,做得很不错,但是要在一个已经开发到一定程度的项目中使用它也不现实,对其它模块影响太大。通过查看它生成的 dom 对象,给了我重要提示。
原来,ligerUI是通过两个 table 实现固定表头的。两个table放在各自的 div 中,前一个用于显示固定表头,后一个显示表的内容;为了避免当单元格内容(包括表头)太长而把单元格撑宽,每个单元格内的内容都嵌套在两层div中,外层的 div 和所在单元格的div保持一至的宽、高,并且设置 style.overflow = hidden,然后内层的div设置足够的宽度,显示单元格的内容:
<th style="width: 100px;" align="left"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Name ssss<div></div> </th>
由于内容框里可能显示垂直滚动条,因此表头需要多一个列,宽度和放置内容table的垂直滚动条相同,大约是22个像素
然后就是需要捕捉内容div的水平滚动条的滚动事件了,当水平滚动条被拖动时,表头的水平位置也同步滚动
$(document).ready(function(){ $("#divBody").scroll(function(eventObj){ var left = $("#divBody").scrollLeft(); $("#divHead").scrollLeft(left); }); });
经测试,在IE、FireFox、Google Chrome, Safari 都运行正常,完整的代码如下,这里用到了js中流行的 jquery,没有的话自己去下吧
<html> <head> <title>Table</title> <script type="text/javascript" src=/blog_article/"jquery1.7.1.js"></script>/index.html <script type="text/javascript"> $(document).ready(function(){ $("#divBody").scroll(function(eventObj){ var left = $("#divBody").scrollLeft(); $("#divHead").scrollLeft(left); }); }); </script> </head> <body> <div style="width:240px; height:200px; border: black solid 1px"> <div id="divHead" style="width:240px; overflow : hidden"> <table id="tbHead" style="width:410px; padding:0px; margin:0px; border-collapse: collapse" border="1" bordercolor="black"> <tr style="height:24px"> <th style="width: 100px;" align="left"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Name ssss<div></div> </th> <th style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </th> <th style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </th> <th></th> </tr> </table> </div> <div id="divBody" style="width: 240px; height: 172px; border: 0px black solid; padding: 0px; margin: 0px; overflow: scroll;"> <table id="tbBody" style="width:280px; padding:0px; margin:0px; border-collapse: collapse" border="1" bordercolor="black"> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </td> </tr> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </td> </tr> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </td> </tr> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </td> </tr> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </td> </tr> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address</div></div> </td> </tr> <tr style="height:24px"> <td style="width: 100px"> <div style="width:100px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Smith<div></div> </td> <td style="width: 140px"> <div style="width:140px; height:24px; overflow: hidden; border:0px; padding:0px; margin:0px"><div style="width:240px; height:24px">Address sssssssss<div></div> </td> <td style="width:140px"> <div style="width:140px; height:24px; overflow:hidden; border:0px; padding:0px; m