在之前的博文,常用框架(一)中讲述了spring+springMvc+mybatis+maven框架的搭建,而在常用框架(二)中又集成了Redis,
这篇文章主要讲述如何集成shiro+freemarker及其简单应用,还是在原有项目上做扩展,
需要回顾的请点链接跳转:http://blog.csdn.net/mynoteblog/article/details/54922775
项目说明:
(1) 使用freemarker模板,在html页面中可以获取attribute参数,替代jsp。
(2) 使用shiro做登录验证,以及权限分配
(3) pom.xml 追加依赖,这里加入了日志框架,源码会分享,这里就不做介绍了:
-
- <dependency>
- <groupId>org.freemarkergroupId>
- <artifactId>freemarkerartifactId>
- <version>2.3.23version>
- dependency>
-
-
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-coreartifactId>
- <version>${shiro.version}version>
- dependency>
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-webartifactId>
- <version>${shiro.version}version>
- dependency>
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-ehcacheartifactId>
- <version>${shiro.version}version>
- dependency>
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-springartifactId>
- <version>${shiro.version}version>
- dependency>
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-freemarker-tagsartifactId>
- <version>0.1-SNAPSHOTversion>
- <exclusions>
- <exclusion>
- <artifactId>javax.servlet-apiartifactId>
- <groupId>javax.servletgroupId>
- exclusion>
- exclusions>
- dependency>
-
-
- <dependency>
- <groupId>org.slf4jgroupId>
- <artifactId>slf4j-apiartifactId>
- <version>${slf4j.version}version>
- dependency>
- <dependency>
- <groupId>ch.qos.logbackgroupId>
- <artifactId>logback-classicartifactId>
- <version>1.1.3version>
- dependency>
- <dependency>
- <groupId>org.slf4jgroupId>
- <artifactId>jcl-over-slf4jartifactId>
- <version>${slf4j.version}version>
- dependency>
- <dependency>
- <groupId>org.slf4jgroupId>
- <artifactId>log4j-over-slf4jartifactId>
- <version>${slf4j.version}version>
- dependency>
- <dependency>
- <groupId>org.logback-extensionsgroupId>
- <artifactId>logback-ext-springartifactId>
- <version>0.1.2version>
- dependency>
一,整合freemarker,新建Spring-freemarker.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:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
-
-
- <bean id="freemarkerConfig"
- class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
-
- <property name="templateLoaderPaths" value="/WEB-INF/template/" />
- <property name="freemarkerSettings">
- <props>
- <prop key="tag_syntax">auto_detectprop>
- <prop key="template_update_delay">0prop>
- <prop key="default_encoding">UTF-8prop>
- <prop key="output_encoding">UTF-8prop>
- <prop key="locale">zh_CNprop>
- <prop key="number_format">0.##########prop>
- <prop key="boolean_format">true,falseprop>
- <prop key="datetime_format">yyyy-MM-dd HH:mm:ssprop>
- <prop key="date_format">yyyy-MM-ddprop>
- <prop key="time_format">HH:mm:ssprop>
- <prop key="classic_compatible">trueprop>
- <prop key="whitespace_stripping">trueprop>
- <prop key="template_exception_handler">ignoreprop>
- props>
- property>
-
- beans>
二,在Spring-config.xml中引入以上新建的配置文件,配置如下:
- <import resource="classpath:Spring-freemarker.xml" />
三,修改Spring-servlet.xml,配置freeMarker视图解析器,如下:
-
- <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
- <property name="contentType" value="text/html; charset=UTF-8" />
- <property name="suffix" value=".ftl" />
- bean>
四,测试,新建hello.ftl页面,代码如下:
- >
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Insert title heretitle>
- head>
- <body>
- [#--从Attribute中获取参数--]
- <h1>${msg}h1>
-
- [#--判断句式--]
- <h1>${(1 == 1)?string("yes", "no")}h1>
-
- [#--集合遍历--]
- <ul>
- [#list list as item]
- <li>${item}li>
- [/#list]
- ui>
-
- [#if msg=='hello']
- <h1>say helloh1>
- [#else]
- <h1>say goodbyeh1>
- [/#if]
-
- body>
- html>
这里用的了[#if],[#list] 指令,其他freemarker常用指令,大家可以百度学习。
五,新建测试Controller,FreemarkerController,代码如下:
- package com.maven.web.controller;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
-
- @Controller
- @RequestMapping("/freemarker")
- public class FreemarkerController {
-
- @RequestMapping(value="/hello",method=RequestMethod.GET)
- public String sayHello(Model model){
- String msg = "Hello World";
- List list = new ArrayList(3);
- list.add("a");
- list.add("b");
- list.add("c");
- model.addAttribute("msg", msg);
- model.addAttribute("list", list);
- return "hello";
- }
-
- }
六,启动tomcat,访问测试:
***************************************************************
单独集成freemarker演示到此结束,下面重点来看shiro集成。
一,添加Spring-shiro.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:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
-
-
- <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
-
- <property name="securityManager" ref="securityManager" />
-
- <property name="loginUrl" value="/template/login.ftl" />
-
- <property name="successUrl" value="/template/main.ftl" />
-
- <property name="unauthorizedUrl" value="/template/error.ftl" />
-
- <property name="filters">
- <map>
- <entry key="logout" value-ref="logoutFilter" />
- <entry key="authc" value-ref="myAuthenticationFilter" />
- map>
- property>
-
- <property name="filterChainDefinitions">
- <value>
-
- /static/** = anon
- /tags/** = anon
-
- /login/**=anon
- /logout = logout
-
- /** = authc
- value>
- property>
- bean>
-
-
- <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
-
- <property name="cacheManager" ref="cacheManager" />
-
- <property name="realm" ref="myRealm" />
- bean>
-
-
- <bean id="myRealm" class="com.maven.web.shiro.MyRealm" />
-
-
- <bean id="myAuthenticationFilter" class="com.maven.web.shiro.MyAuthenticationFilter" />
-
-
- <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
- <property name="redirectUrl" value="/template/login.ftl" />
- bean>
-
-
- <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
-
-
- <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
-
- beans>
*********************************************************************************************************************
这里需要注意:
默认的shiro authc 认证参数是username+password,我这里重写了认证方法,改为认证phone+password,
如果没有此需要的,去掉上面配置文件中的以下配置即可,采用默认过滤器
同理,其他anon,logout过滤器也可以重写,还可以自定义过滤器,这些大家可以根据需要来实现,不多介绍。
二,在web.xml 中添加shiro核心过滤器,配置如下:
-
- <filter>
- <filter-name>shiroFilterfilter-name>
- <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
- <init-param>
- <param-name>targetFilterLifecycleparam-name>
- <param-value>trueparam-value>
- init-param>
- filter>
- <filter-mapping>
- <filter-name>shiroFilterfilter-name>
- <url-pattern>/*url-pattern>
- filter-mapping>
三,在Spring-config.xml中引入shiro配置文件,配置如下:
- <import resource="classpath:Spring-shiro.xml" />
四,重写自己的Realm授权+认证方法,在此之前,先实现我们需要的认证参数。
(一) 新建MyAuthenticationToken继承UsernamePasswordToken,添加我们需要的phone属性,代码如下:
(如果不需要自定义属性就不需要写这一步了,直接用UsernamePasswordToken即可)
- package com.maven.web.shiro;
-
- import org.apache.shiro.authc.UsernamePasswordToken;
-
-
-
-
-
-
- public class MyAuthenticationToken extends UsernamePasswordToken{
-
- private static final long serialVersionUID = 1425855488092920451L;
-
-
- private String phone;
-
- public MyAuthenticationToken(String phone, String password, boolean rememberMe, String host) {
- super(null, password, rememberMe, host);
- this.phone = phone;
- }
-
-
- @Override
- public Object getPrincipal() {
- return phone;
- }
-
- @Override
- public void clear() {
- super.clear();
- phone = null;
- }
-
- public String getPhone() {
- return phone;
- }
-
- public void setPhone(String phone) {
- this.phone = phone;
- }
-
-
-
- }
(二) 新建MyAuthenticationFilter继承FormAuthenticationFilter,实现用户认证,代码如下:
- package com.maven.web.shiro;
-
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
-
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
- import org.apache.shiro.web.util.WebUtils;
-
-
-
-
-
-
- public class MyAuthenticationFilter extends FormAuthenticationFilter{
-
- public static final String DEFAULT_PHONE_PARAM = "phone";
-
- private String phoneParam = DEFAULT_PHONE_PARAM;
-
- public MyAuthenticationFilter(){
- setFailureKeyAttribute(DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
- }
-
- @Override
- protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
- String phone = getPhone(request);
- String password = getPassword(request);
- boolean rememberMe = isRememberMe(request);
- String host = getHost(request);
-
- return new com.maven.web.shiro.MyAuthenticationToken(phone,password,rememberMe,host);
- }
-
- public String getPhoneParam() {
- return phoneParam;
- }
-
- public void setPhoneParam(String phoneParam) {
- this.phoneParam = phoneParam;
- }
-
- protected String getPhone(ServletRequest request) {
- return WebUtils.getCleanParam(request, getPhoneParam());
- }
-
- }
(三) 新建自己的Realm类,MyRealm 继承AuthorizingRealm,代码如下:
*******************************************************************************************************************
这里说明一下:
认证方法,是对用户在登录页面提交的信息做校验,登录成功才会跳转到主页。
授权方法,用户登录成功后可以根据用户信息查找相关角色,权限,存储到授权对象中。
以后就可以通过Java代码,shiro标签等,获取当前用户的角色,权限,进行模块功能分配等等。下面会演示。
五,用户登录
(一) 新建登录页面,login.ftl,代码如下:
- >
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Insert title heretitle>
- head>
- <body>
- <form action="/com.maven.web/login/login" method="post" id="form">
- <article>手机号:article>
- <input type="text" name="phone"/>
- <article>密码:article>
- <input type="password" name="password"/>
- <br/>
- <br/>
- <input type="submit" value="登录" />
- <br/>
- form>
- <span style="color:red">${msg}span>
- body>
- html>
(二) 新建 LoginContoller,代码如下:
- package com.maven.web.controller;
-
- import javax.servlet.http.HttpServletRequest;
-
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.subject.Subject;
- import org.slf4j.Logger;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
-
- import com.maven.web.entity.UserInfo;
- import com.maven.web.shiro.MyAuthenticationToken;
- import com.maven.web.util.LoggerUtils;
-
- @Controller
- @RequestMapping("/login")
- public class LoginController {
- private final Logger logger = LoggerUtils.getLogger("LoginController");
-
-
-
-
-
-
-
-
- @RequestMapping(value="/login",method=RequestMethod.POST)
- public String checkLogin(UserInfo userInfo,Model model,HttpServletRequest request){
-
- logger.debug("userInfo", userInfo);;
-
- MyAuthenticationToken token = new MyAuthenticationToken(userInfo.getPhone(), userInfo.getPassword(), true, null);
- Subject subject = SecurityUtils.getSubject();
- try {
- subject.login(token);
- if(subject.isAuthenticated()){
- return "redirect:/menu/list";
- }else{
- token.clear();
- }
- }catch(AuthenticationException e){
- model.addAttribute("msg",e.getMessage());
- }
- return "login";
- }
-
-
-
-
- @RequestMapping("/logout")
- public String logout(){
- SecurityUtils.getSubject().logout();
- return "login";
- }
- }
(三) 新建登录成功页面,main.ftl,代码如下:
- >
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Insert title heretitle>
- head>
- <body>
- <span>菜单栏span>
- <ul>
- [#list menus as menu]
- <li><a href="#">${menu.menuParent.menuName}a>li>
- <li>
- <ul>
- [#list menu.menuChilds as menuChild]
- <li><a href=${menuChild.menuUrl}>${menuChild.menuName}a>li>
- [/#list]
- ul>
- li>
- [/#list]
- ul>
- <span>${msg}span>
- <br/>
- <div>
- [@shiro.hasRole name="管理员"]
- <span>角色是管理员才能看到此信息span>
- [/@shiro.hasRole]
- div>
- <a href="/com.maven.web/login/logout">logouta>
- body>
- html>
(四) 新建MenuController,动态查询菜单权限返回主页面main.ftl,代码如下:
- package com.maven.web.controller;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import javax.annotation.Resource;
-
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.subject.Subject;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
-
- import com.maven.web.entity.MenuChild;
- import com.maven.web.entity.MenuParent;
- import com.maven.web.mapper.MenuChildMapper;
- import com.maven.web.mapper.MenuParentMapper;
- import com.maven.web.vo.Menu;
-
- @Controller
- @RequestMapping("/menu")
- public class MenuController {
-
- @Resource
- private MenuParentMapper menuParentMapper;
-
- @Resource
- private MenuChildMapper menuChildMapper;
-
- @RequestMapping(value="/list",method=RequestMethod.GET)
- public String listMenu(Model model){
- List
- List parents = menuParentMapper.getMenuParentList();
- if(parents!=null && !parents.isEmpty()){
- for(MenuParent parent:parents){
- Menu menu = new Menu();
- menu.setMenuParent(parent);
- List childs = menuChildMapper.getMenuChildByPid(parent.getId());
- if(childs!=null && !childs.isEmpty()){
- menu.setMenuChilds(childs);
- }
- menus.add(menu);
- }
- }
- model.addAttribute("menus",menus);
- Subject subject = SecurityUtils.getSubject();
- if(subject.hasRole("管理员")){
- model.addAttribute("msg","这里是管理员私人信息!");
- }
- return "main";
- }
-
- }
六,启动tomcat,测试:
这里先给大家看一下我数据库的用户信息:
启动访问,未登录会跳转到登录页面
测试一:错误用户信息
测试二:新注册用户状态为未激活
测试三:管理员登录
测试四:普通用户登录
*******************************************************************************************************
这里请大家注意,管理员登录成功后可以看到红色框和黄色框两条信息,普通用户登录后看不到。
(1) 红色框信息:
这是因为在MenuController中做了角色判断,注意代码片段:
- Subject subject = SecurityUtils.getSubject();
- if(subject.hasRole("管理员")){
- model.addAttribute("msg","这里是管理员私人信息!");
- }
(2) 黄色框信息:
这是因为在main.ftl页面中使用了shiro标签,注意代码片段:
- <div>
- [@shiro.hasRole name="管理员"]
- <span>角色是管理员才能看到此信息span>
- [/@shiro.hasRole]
- div>
********************************************************************************************************
接下来说明shiro标签的使用:
(一) 在freemarker中需要先引入shiro-freemarker-tags-0.1-SNAPSHOT.jar,本例已经添加到pom.xml文件中,
大家可以下载源码,在lib中找到jar包添加到本地,也可以到网上下载,下面会贴出链接。
(二) 新建CustomFreeMarkerConfigurer 继承FreeMarkerConfigurer,代码如下:
- package com.maven.web.template;
-
- import java.io.IOException;
-
- import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
-
- import com.jagregory.shiro.freemarker.ShiroTags;
-
- import freemarker.template.TemplateException;
-
-
-
-
-
-
- public class CustomFreeMarkerConfigurer extends FreeMarkerConfigurer{
-
-
-
-
-
- @Override
- public void afterPropertiesSet() throws IOException, TemplateException {
- super.afterPropertiesSet();
- this.getConfiguration().setSharedVariable("shiro", new ShiroTags());
- }
- }
(三) 修改Spring-freemarker.xml配置文件,改成自定义的CustomFreeMarkerConfigurer
关于shiro标签与freemarker的整合,大家可以跳转链接学习:http://blog.csdn.net/lingyundouer/article/details/50487459
如果使用默认的authc认证,只需要将代码中MyAuthenticationToken替换成UsernamePasswordToken,
然后获取到的phone参数替换成username就可以,其他都是一样的。
以上就介绍完毕了,可能有所遗漏,大家可以下载源码参考:http://pan.baidu.com/s/1dFilb6h