常用框架(三):spring+springMvc+mybatis+maven+shiro+freemarker
来源:互联网 发布:编程验证歌德巴赫猜想 编辑:程序博客网 时间:2024/05/19 20:22
在之前的博文,常用框架(一)中讲述了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 追加依赖,这里加入了日志框架,源码会分享,这里就不做介绍了:
<!-- freemarker --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.23</version></dependency><!-- Spring 整合Shiro需要的依赖 --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-freemarker-tags</artifactId><version>0.1-SNAPSHOT</version><exclusions><exclusion><artifactId>javax.servlet-api</artifactId><groupId>javax.servlet</groupId></exclusion></exclusions></dependency><!-- slf4j日志框架 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.3</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.logback-extensions</groupId><artifactId>logback-ext-spring</artifactId><version>0.1.2</version></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"><!-- 配置freeMarker的模板路径 --><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_detect</prop> <prop key="template_update_delay">0</prop> <prop key="default_encoding">UTF-8</prop> <prop key="output_encoding">UTF-8</prop> <prop key="locale">zh_CN</prop> <prop key="number_format">0.##########</prop> <prop key="boolean_format">true,false</prop> <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop> <prop key="date_format">yyyy-MM-dd</prop> <prop key="time_format">HH:mm:ss</prop> <prop key="classic_compatible">true</prop> <prop key="whitespace_stripping">true</prop> <prop key="template_exception_handler">ignore</prop> </props> </property></beans>
二,在Spring-config.xml中引入以上新建的配置文件,配置如下:
<import resource="classpath:Spring-freemarker.xml" />
三,修改Spring-servlet.xml,配置freeMarker视图解析器,如下:
<!-- 配置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页面,代码如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></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 hello</h1>[#else]<h1>say goodbye</h1>[/#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<String> list = new ArrayList<String>(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"><!-- Shiro主过滤器的拦截 --><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 <!-- 对所有url都需要进行认证 --> /** = authc</value></property></bean><!-- 配置权限管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><!-- 缓存管理器 --> <property name="cacheManager" ref="cacheManager" /><!-- 我们自定义的realm --><property name="realm" ref="myRealm" /></bean> <!-- 自定义的Realm,若有多个Realm,可使用'realms'属性代替 --> <bean id="myRealm" class="com.maven.web.shiro.MyRealm" /> <!-- 重写的认证filter--> <bean id="myAuthenticationFilter" class="com.maven.web.shiro.MyAuthenticationFilter" /> <!-- 使用shiro提供的logout filter --> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="/template/login.ftl" /> </bean> <!-- shiro 缓存管理 --> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <!-- Shiro生命周期处理器 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans>*********************************************************************************************************************
这里需要注意:
默认的shiro authc 认证参数是username+password,我这里重写了认证方法,改为认证phone+password,
如果没有此需要的,去掉上面配置文件中的以下配置即可,采用默认过滤器
同理,其他anon,logout过滤器也可以重写,还可以自定义过滤器,这些大家可以根据需要来实现,不多介绍。
二,在web.xml 中添加shiro核心过滤器,配置如下:
<!-- shiro过滤器 --><filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><init-param><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>
三,在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;/** * 重新token,对用户名的认证改为手机号 * @author Administrator * */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;}/** 默认是返回用户名,改写返回手机号 */@Overridepublic Object getPrincipal() {return phone;}@Overridepublic 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;/** * 重写token认证 * @author Administrator * */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);}@Overrideprotected 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,代码如下:
package com.maven.web.shiro;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import javax.annotation.Resource;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.DisabledAccountException;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import com.maven.web.entity.MenuChild;import com.maven.web.entity.RoleInfo;import com.maven.web.entity.UserInfo;import com.maven.web.exception.AuthenticateException;import com.maven.web.mapper.MenuChildMapper;import com.maven.web.mapper.RoleInfoMapper;import com.maven.web.service.impl.UserService;public class MyRealm extends AuthorizingRealm{@Resourceprivate UserService userService;@Resourceprivate MenuChildMapper menuChildMapper;@Resourceprivate RoleInfoMapper roleInfoMapper;public MyRealm() {setAuthenticationTokenClass(AuthenticationToken.class);}/** * 重写认证方法 */@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {UserInfo userInfo = null;if(token instanceof MyAuthenticationToken){MyAuthenticationToken myToken = (MyAuthenticationToken) token;String phone = myToken.getPhone();String password = new String(myToken.getPassword());try {userInfo = userService.getUserInfoNyPhone(phone,password);} catch (AuthenticateException e){throw new IncorrectCredentialsException(e);}if (null == userInfo) {throw new IncorrectCredentialsException("账号或密码错误!");}if (!"0".equals(userInfo.getStatus())) {throw new DisabledAccountException("帐号"+myToken.getPrincipal()+"已失效!");}//比对成功则返回authcInfo AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(userInfo, userInfo.getPassword().toCharArray(),this.getName()); // this.setSession("currentUser", userInfo); return authcInfo; }return null;} /** * 为认证成功的用户授权,然后就可以调用subject.hasRole等方法进行逻辑判断 */ @Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //认证通过后会将需要的身份信息放到SimpleAuthenticationInfo中返回,这是是获取到其中的principal对象 Iterator<?> iterator = principals.fromRealm(getName()).iterator(); if (iterator.hasNext()) { UserInfo userInfo = (UserInfo) iterator.next(); if (null != userInfo) { List<String> roleList = new ArrayList<String>(); List<String> permissionList = new ArrayList<String>(); //查询用户角色 RoleInfo userRole = roleInfoMapper.selectByUserId(userInfo.getId()); if(null !=userRole){ roleList.add(userRole.getRoleName()); List<MenuChild> roleMenus = menuChildMapper.getMenuChildByRoleId(userRole.getId()); if(null !=roleMenus){ for(MenuChild menu:roleMenus){ permissionList.add(menu.getMenuName()); } } } //为用户添加权限,角色 SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo(); simpleAuthorInfo.addRoles(roleList); simpleAuthorInfo.addStringPermissions(permissionList); return simpleAuthorInfo; } } return null;} /** * 将一些数据放到ShiroSession中,以便于其它地方使用 * @see 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到 * 也可以直接从subject的身份对象中取 */ /* private void setSession(Object key, Object value){ Subject currentUser = SecurityUtils.getSubject(); if(null != currentUser){ Session session = currentUser.getSession(); System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒"); if(null != session){ session.setAttribute(key, value); } } }*/}*******************************************************************************************************************
这里说明一下:
认证方法,是对用户在登录页面提交的信息做校验,登录成功才会跳转到主页。
授权方法,用户登录成功后可以根据用户信息查找相关角色,权限,存储到授权对象中。
以后就可以通过java代码,shiro标签等,获取当前用户的角色,权限,进行模块功能分配等等。下面会演示。
五,用户登录
(一) 新建登录页面,login.ftl,代码如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></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");/** * 基于手机号和密码的身份认证 * @param userInfo * @param model * @param request * @return */@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);//会到自定义的Realm中进行验证返回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,代码如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></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">logout</a></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 {@Resourceprivate MenuParentMapper menuParentMapper; @Resourceprivate MenuChildMapper menuChildMapper; @RequestMapping(value="/list",method=RequestMethod.GET)public String listMenu(Model model){List<Menu> menus = new ArrayList<Menu>();List<MenuParent> parents = menuParentMapper.getMenuParentList();if(parents!=null && !parents.isEmpty()){for(MenuParent parent:parents){Menu menu = new Menu();menu.setMenuParent(parent);List<MenuChild> 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;/** * 编写自己的freemarker配置 * @author Administrator * */public class CustomFreeMarkerConfigurer extends FreeMarkerConfigurer{/** * 重写导入shiro标签 */@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
- 常用框架(三):spring+springMvc+mybatis+maven+shiro+freemarker
- 常用框架(三):spring+springMvc+mybatis+maven+shiro+freemarker
- 常用框架(三):spring+springMvc+mybatis+maven+shiro+freemarker
- 常用框架(一):spring+springMvc+mybatis+maven
- 常用框架(一):spring+springMvc+mybatis+maven
- 常用框架(一):spring+springMvc+mybatis+maven
- 【ssm框架】 spring+springMVC+mySQL+myBatis+freemarker+Maven小示例
- 发布一个demo maven+freemarker+shiro+springmvc+spring+mybatis+redis+mysql
- spring+freemarker+springMvc+mybatis+maven整合
- shiro + springMVC + spring + mybatis (maven 整合)
- Spring+SpringMVC+Mybatis+Shiro框架整合-yellowcong
- 常用框架(二) : spring+springMvc+mybatis+maven+redis
- 常用框架(二) : spring+springMvc+mybatis+maven+redis
- 常用框架(二) : spring+springMvc+mybatis+maven+redis
- SpringMvc + Mybatis + Maven + Freemarker
- 集成Spring+SpringMVC+Mybatis+Shiro+Maven+JUnit的Java Web框架
- java框架整合Springmvc+mybatis+shiro+lucene+rest+webservice+maven
- 系统框架 springmvc mybatis Bootstrap html5 shiro maven
- UTC和时区
- 解决java未赋值变量的默认值问题
- 卷积神经网络(CNN)前向传播算法
- PAT A1125. Chain the Ropes (25)(哈夫曼树)
- iOS微信安装包瘦身
- 常用框架(三):spring+springMvc+mybatis+maven+shiro+freemarker
- 国外15款开源免费软件
- hough变换 正在的c代码风格实现
- xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Deve
- typedef
- 前端资源集合
- 【javaScript学习之一】string函数slice()学习
- 动手开发一个名为“微天气”的微信小程序(上)
- Qt使用上一次打开的路径