王朝网络
分享
 
 
 

SpringMvc-Httl-shiro的整合

王朝学院·作者佚名  2016-05-28  
宽屏版  字体: |||超大  

SPRingMvc-Httl-shiro的整合来到新的公司一个月,以前实习公司的用的是srping+hibernate+struts2,而在这里不在用的这些了,而是用的springMVC和jdbc模板来操作数据了,所以又用了一段时间去慢慢融入这个新的体系中去;但终究这些技术是万变不离其宗的,学习也是很快的事,所以我也就很快的就融入了这个团队;

进入正题吧!我这里其实就是想把学习新东西自己记录下来,这有助于我的学习也有助于大家的学习;把springmvc+httl+shiro+maven给整合起来;我刚来到新公司这里已经是搭建好了这个项目;所以我也在空闲时间之余把这些知识给过了一遍,也有助于我开发效率的提高;

我使用的开发工具室MyEclipse(开发工具的使用都是大同小异);

至于httl和shiro的优势我就不多说了有兴趣的看:

http://www.open-open.com/open342321.htm;

http://blog.csdn.net/boonya/article/details/8233303

废话不多说,开始搭建吧。。。

1:首先建立一个javaweb项目

2:配置pom.xml导入必须的jar包

<dependencies> <!-- junit核心jar包 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- springMVC核心jar包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.5.RELEASE</version> </dependency> <!-- httl 核心jar包 --> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl-springmvc</artifactId> <version>1.0.10</version> </dependency> <dependency> <groupId>com.github.httl</groupId> <artifactId>httl</artifactId> <version>1.0.11</version> </dependency> <!--当你运行的环境是jre是时;httl模板必须加入这个jar包;还有就是必须在httl的 httl.properties注入属性值: compiler=httl.spi.compilers.JavassistCompiler。。这点很重要,不然当你启动tomcat时会一直抛classnotfound异常--> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.18.2-GA</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <!-- spring aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.5</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.5</version> </dependency> </dependencies>

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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name></display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext-shiro.xml </param-value> </context-param> <!-- 配置Shiro过滤器,先让Shiro过滤系统接收到的请求 --> <!-- 这里filter-name必须对应applicationContext.xml中定义的<bean id="shiroFilter" /> --> <!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 --> <!-- 通常会将此filter-mapping放置到最前面(即其他filter-mapping前面),以保证它是过滤器链中第一个起作用的 --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 --> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 加载httl的属性文件 --> <context-param> <param-name>httl.properties</param-name> <param-value>classpath:httl.properties</param-value> </context-param> <!-- Character Encoding filter --> <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> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> <!-- Spring MVC Servlet 载入 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 实例化Spring容器 --> <!-- 应用启动时,该监听器被执行,它会读取Spring相关配置文件,其默认会到WEB-INF中查找applicationContext.xml --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>

4:添加httl.properties文件

import.packages+=com.lishun.controller

template.directory=/WEB-INF/templates

template.suffix=.httl

input.encoding=utf-8

output.encoding=utf-8

reloadable=true

precompiled=true

compiler=httl.spi.compilers.JavassistCompiler

import.methods+=com.lishun.httl.staticMethods.ShiroKit

注:import.packages:领域模型包导入

import.methods:这里可以封装在httl模板页面上使用的静态方法

template.directory:模板文件目录;

template.suffix:模板文件后缀

input.encoding:资源加载编码

output.encoding: 模板输出编码

precompiled:是否预编译

reloadable: 是否热加载;开发模式下建议开启

compiler:(摘自httl官网)

用于将模板类编译成字节码,缺省使用根据JDK版本自适应编译器:(缺省值不用配)

1

compiler=httl.spi.compilers.AdaptiveCompiler

当前运行环境为JDK1.6以前版本时,AdaptiveCompiler将适配到JavassistCompiler,否则将适配到JdkCompiler。

你可以强制指定使用jdk自带的编译器:(必需要用JDK运行,JRE不行,JDK比JRE多编译工具包)

1

compiler=httl.spi.compilers.JdkCompiler

你也可以换成javassist编译:(如果为JRE运行,请使用javassist编译)

1

compiler=httl.spi.compilers.JavassistCompiler

当然,也就需要增加javassist的jar包依赖:

javassist-3.15.0-GA.jar

<dependency>

<groupId>org.javassist</groupId>

<artifactId>javassist</artifactId>

<version>3.15.0-GA</version>

</dependency>

5:编写applicationContext-shiro.xml 注:该文件是管理shiro的

<!-- 这里别忘了配置,否则会导致自定义的Realm的属性值无法注入 --> <context:component-scan base-package="com.lishun"></context:component-scan> <!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的UserRealm.java --> <bean id="shiroRealm" class="com.lishun.shiro.realm.UserRealm" > </bean> <!-- 基于Form表单的身份验证过滤器 --> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="usernameParam" value="username" /> <property name="passWordParam" value="password" /> <property name="loginUrl" value="/users/index.html" /> <property name="successUrl" value="/index/index.html" /> </bean> <context:component-scan base-package="com.lishun"></context:component-scan> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroRealm" /> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 调用自定义的权限管理器 --> <property name="securityManager" ref="securityManager" /> <!-- 配置登陆成功后跳转地址 --> <property name="successUrl" value="/index/index" /> <!-- 配置登陆时请求的地址 --> <property name="loginUrl" value="/users/index" /> <!-- 如果请求的资源不再你的权限范围内,则跳转到error.htm --> <property name="unauthorizedUrl" value="/users/noAuth" /> <property name="filters"> <map> <entry key="authc" value-ref="formAuthenticationFilter"></entry> </map> </property> <property name="filterChainDefinitions"> <value> <!-- anon表示此地址不需要任何权限即可访问 --> /users/*=anon <!--login页面和logout页面不需要验证 --> /login* = anon <!--访问所有文件,authc必须通过验证后才能访问 --> /** = authc </value> </property> </bean> <!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager" /> <property name="arguments" ref="securityManager" /> </bean> <!-- Shiro生命周期处理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

6.编写spring-mvc.xml文件 注:该文件是管理springmvc的

<!-- 自动扫描且只扫描@Controller --> <context:component-scan base-package="com.lishun" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" /> </context:component-scan> <!-- 启用SpringMVC的注解功能,它会自动注册HandlerMapping、HandlerAdapter、ExceptionResolver的相关实例 --> <mvc:annotation-driven /> <!-- 配置SpringMVC的视图解析器 httl视图 --> <bean id="viewResolver" class="httl.web.springmvc.HttlViewResolver"> <property name="contentType" value="text/html; charset=UTF-8" /> </bean> <!-- 在spring-mvc.xml配置文件添加Shiro Spring AOP权限注解的支持: --> <aop:config proxy-target-class="true"></aop:config> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> <!-- 当前用户没有权限时跳转到的页面: --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException">/users/unauthorizedView</prop> </props> </property> </bean>

7:编写用户实体(User)和角色实体(Role)

public class User { private String name; private String password; private Role role; @Override public String toString() { return "User [name=" + name + ", password=" + password + ", role=" + role + "]"; } public String getName() { return name; } public User() { super(); } public void setName(String name) { this.name = name; } public User(String name, String password) { super(); this.name = name; this.password = password; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Role getRole() { return role; } public void setRole(Role role) { this.role = role; }}---------------------------------------------------分割线public class Role { private String roleName; private Set<String> rolePermissions; public Set<String> getRolePermissions() { return rolePermissions; } public void setRolePermissions(Set<String> rolePermissions) { this.rolePermissions = rolePermissions; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; }}

8:在httl模板上执行静态函数的类

/* * 在httl模板上可以直接使用的函数 */public class ShiroKit { /** * 禁止初始化 */ private ShiroKit() { } /** * 获取 Subject * * @return Subject */ protected static Subject getSubject() { return SecurityUtils.getSubject(); } /** * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用 * * @param permission * 权限名 * @return 拥有权限:true,否则false */ public static boolean hasPermission(String permission) { boolean ret = getSubject() != null && permission != null && permission.length() > 0 && getSubject().isPermitted(permission); return ret; } /** * 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。 * * @param permission * 权限名 * @return 拥有权限:true,否则false */ public static boolean lacksPermission(String permission) { return !hasPermission(permission); }}

9:自定义用户验证规则(必须继承AuthorizingRealm)

public class UserRealm extends AuthorizingRealm { @Autowired @Qualifier("userDao") private UserDao userDao; /* * 权限认证 */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { // 根据用户配置用户与权限 if (principals == null) { throw new AuthorizationException( "PrincipalCollection method argument cannot be null."); } String name = (String) getAvailablePrincipal(principals); List<String> roles = new ArrayList<String>(); User user = userDao.getUserByName(name); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 把当前用户的角色保存到Subject中 roles.add(user.getRole().getRoleName()); info.addRoles(roles); // 把当前用户的权限保存到Subject中 info.setStringPermissions(user.getRole().getRolePermissions()); return info; } /* * 登陆认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; //获取页面输入用户名 String username=(String) token.getPrincipal(); //从dao层获取该用户 System.out.println(userDao); User user = userDao.getUserByName(username); if (user == null) { throw new AuthorizationException(); } SimpleAuthenticationInfo info = null; //存储令牌信息 if (user.getName().equals(token.getUsername())) { info = new SimpleAuthenticationInfo(user.getName(), user.getPassword(), getName()); } return info; } }

10:编写dao层

/* * 这里我就不查询数据数据了,侧重点不在这里,所以写死用户数据 */public class UserDao { private static List<User> list=new ArrayList<User>(); private static Set<String> userPermissions=new HashSet<String>(); private static Set<String> adminPermissions=new HashSet<String>(); static { //lishun普通用户 User lishun =new User(); lishun.setName("lishun"); lishun.setPassword("123"); Role lishunRole=new Role(); lishunRole.setRoleName("user"); //lishun普通用户只拥有一个权限 userPermissions.add("user:lishun:view"); lishunRole.setRolePermissions(userPermissions); lishun.setRole(lishunRole); //admin超级用户 User admin =new User(); admin.setName("admin"); admin.setPassword("123"); Role adminRole=new Role(); adminRole.setRoleName("admin"); //admin用户拥有所有权限 adminPermissions.add("user:lishun:view"); adminPermissions.add("manager:lishun:view"); adminRole.setRolePermissions(adminPermissions); admin.setRole(adminRole); list.add(admin); list.add(lishun); } public User getUserByName(String name){ for (User u : list) { if(u.getName().equals(name)){ return u; } } return null; }

11:编写控制器:用户登陆控制器

//不用任何权限都可以访问该控制器的方法@Controllerpublic class UserController { /* * 登陆页面 */ @RequestMapping(value = "users/index", method = RequestMethod.GET) public String index() { return "users/login"; } /* * 验证用户 */ @RequestMapping(value = "users/login", method = RequestMethod.POST) public String login(String username,String password,Model model){ //获取到当前用户的的Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); String error = null; try { //验证登陆 subject.login(token); } catch (AuthenticationException e) { error = "warning message:Login failed,please check your username and password"; model.addAttribute("errorMessage", error); } if (error==null) { return "redirect:../index/index"; } else { return "redirect:index"; } } /* * 没有权限后跳转的页面 */ @RequestMapping(value = "users/unauthorizedView", method = RequestMethod.GET) public String unauthorizedView() { return "users/unauthorizedView"; }}

12:login.httl文件

<!--#set(String msg="httl模板测试") --><!--#set(String manageHost = request.getScheme()+"://"+request.serverName+":"+"a".valueOf(request.serverPort)+request.getContextPath())--><html><body> <form action="${manageHost}/users/login" method="post"> <label style="color: red">${errorMessage}</label> <table> <tr> <td>UserName:</td> <td><input type="text" name="username" /> </td> </tr> <tr> <td>Password:</td> <td><input type="password" name="password" /> </td> </tr> <tr> <td colspan="2"><input type="submit" value="Login" /> </td> </tr> </table> </form></body></html> -----------------------分隔符

至于httl的语法大家可以去官网上浏览,我这里就不多说,http://httl.github.io/zh/syntax.html

打开url:http://localhost:8080/SpringMvc-Httl-shiro/users/login

就可以浏览了

13 编写控制器:用户主页控制器

@Controllerpublic class IndexController { /* * 普通用户就可以访问该页面 */ @RequiresPermissions("user:lishun:view") @RequestMapping(value = "index/index", method = RequestMethod.GET) public String index() { System.out.println(SecurityUtils.getSubject().isPermitted("user:lishun:view")); return "index/index"; }}-------------------------------------------分割线

用户主页模板index.httl

<!--#set(String msg="httl模板测试") --><!--#set(String manageHost = request.getScheme()+"://"+request.serverName+":"+"a".valueOf(request.serverPort)+request.getContextPath())--><html><body> #if(hasPermission("manager:lishun:view")) 超级用户登陆 <a href="${manageHost}/manager/user">管理用户</a> #else(hasPermission("user:lishun:view")) 普通用户登陆 #end</body></html>

14 编写控制器:管理员控制器

@Controller@RequestMapping("manager")public class ManagerController { /* * 只有管理员才有权限查看本页面 */ @RequiresPermissions("manager:lishun:view") @RequestMapping(value = "/user", method = RequestMethod.GET) public String index() { return "manager/userManager"; } }-------------------------------------------分割线

管理用户模板userManager.httl

<!--#set(String msg="httl模板测试") --><!--#set(String manageHost = request.getScheme()+"://"+request.serverName+":"+"a".valueOf(request.serverPort)+request.getContextPath())--><html><body> <h1>只有admin角色才可以访问</h1></body></html>

当你是普通用户访问该页面时因没有权限而跳转到无权限页面

由于本人水平有限,若文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!希望能互相学习。需要源码的留下邮箱

最后附上项目的目录结构

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有