编程语言
首页 > 编程语言> > Marco's Java【Shiro进阶(一) 之 Shiro+SMM集成Maven项目串烧篇(中)】

Marco's Java【Shiro进阶(一) 之 Shiro+SMM集成Maven项目串烧篇(中)】

作者:互联网

前言

前面一节我们将Shiro+SMM集成Maven项目的MVC基本 “骨架” 构建好了,那么本节就是往里面注入"灵魂",让程序能够顺利跑起来,大家还是继续跟着我的思路走吧~

SMM及Shiro集成配置文件

第十四式:导入配置文件
其实到目前为止,我们的这个 “小项目” 整体框架已经搭差不多啦,但是还剩下最后一个步骤没有做 ,就是配置文件,别项目做着做着忘了配置,结果一运行就哭了,哈哈,把配置放到这里来讲主要是想带着大家走一遍过场,知道我们有什么再来配置,否则真的会一脸懵逼。看完我前面Spring系列博文的朋友这些配置应该不在话下啦

1)application-dao.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.xsd">
	
	<context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="FALLBACK"/>
	<!-- alibaba Druid数据库连接池 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName" value="${driverClassName}"></property>
		<property name="url" value="${url}"></property>
		<property name="username" value="${username}"></property>
		<property name="password" value="${password}"></property>
		<!-- 设置最大连接数 -->
		<property name="maxActive" value="50"></property>
		<!-- 设置初始化数量 -->
		<property name="initialSize" value="10"></property>
		<!-- 设置最大等待时长 -->
		<property name="maxWait" value="5000"></property>
		<!-- 注入过滤器,关键的一步,开启Druid的监控统计功能  -->
		<property name="filters" value="stat"></property>
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
  		<property name="timeBetweenEvictionRunsMillis" value="50000" />
  		<!-- 配置连接的最小生存时间,单位是毫秒 -->
  		<property name="minEvictableIdleTimeMillis" value="300000" />
	</bean>
	
	<!-- 声明sessionFactory  并注入mybatis.config.xml(mybatis基本配置文件)-->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 注入数据源 -->
		<property name="dataSource" ref="dataSource"></property>
		<property name="mapperLocations">
			<array>
				<value>classpath:mapper/*Mapper.xml</value>
			</array>
		</property>
		<property name="plugins">
			<array>
				<bean class="com.github.pagehelper.PageInterceptor"></bean>
			</array>
		</property>
	</bean>
	<!-- 扫描mapper接口 将sqlSessionFactory注入到mapper中 实现接口和配置文件的关联 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 注入Mapper接口所在的包-->
		<property name="basePackage">
			<value>
				com.marco.mapper
			</value>
		</property>
		<!-- 注入sqlSessionFactory -->
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	</bean>
</beans>

2)application-service.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"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

	<context:component-scan base-package="com.marco.service.impl"></context:component-scan>
	<!-- 1,声明事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 启动注解事务 -->
	<tx:annotation-driven/>
	<!-- 2,声明事务的传播特性 也就是通知 -->
	<tx:advice id="advice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="insert*" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
			<tx:method name="edit*" propagation="REQUIRED"/>
			<tx:method name="verify*" propagation="REQUIRED"/>
			<tx:method name="reset*" propagation="REQUIRED"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="upload*" propagation="REQUIRED"/>
			<tx:method name="select*" read-only="true"/>
			<tx:method name="get*" read-only="true"/>
			<tx:method name="query*" read-only="true"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	<!-- 3进行AOP织入 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.marco.service.impl.*.*(..))" id="point"/>
		<aop:advisor advice-ref="advice" pointcut-ref="point"/>
	</aop:config>
</beans>

上面两个配置没啥好说的,接下的配置大家就要留意啦,都是和Shiro集成相关的配置,每一个标签的意思我都在标签上注明了

3)application-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: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.xsd">
	
		<!-- 声明凭证匹配器 -->
	<bean id="credentialsMatcher"
		class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<!-- 注入算法 -->
		<property name="hashAlgorithmName" value="md5"></property>
		<!-- 注入散列次数 -->
		<property name="hashIterations" value="2"></property>
	</bean>

	<!-- 声明realm -->
	<bean id="userRealm" class="com.marco.realms.UserRealm">
		<!-- 注入凭证匹配器 -->
		<property name="credentialsMatcher" ref="credentialsMatcher"></property>
	</bean>

	<!-- 创建安全管理器 -->
	<bean id="securityManager"
		class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- 注入realm -->
		<property name="realm" ref="userRealm"></property>
	</bean>
	

	<!-- 配置过滤器链 -->
	<!-- Shiro 的Web过滤器 id必须和web.xml里面的shiroFilter的 targetBeanName的值一样 -->
	<bean id="shiroFilter"
		class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!-- Shiro的核心安全接口,这个属性是必须的 -->
		<property name="securityManager" ref="securityManager" />
		<!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
		<property name="loginUrl" value="/index.jsp" />
		<!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在UserController里硬编码) -->
		<!-- <property name="successUrl" value="/success.action"/> -->
		<!-- 用户访问未对其授权的资源时,所显示的连接 -->
		<property name="unauthorizedUrl" value="/unauthorized.jsp" />
		<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
		<property name="filterChainDefinitions">
			<value>
				<!-- /** = authc 所有url都必须认证通过才可以访问 -->
				/index.jsp*=anon
				/login/toLogin*=anon
				/login/login*=anon
				<!-- 如果用户访问user/logout就使用Shiro注销session -->
				/login/logout = logout
				<!-- /** = anon所有url都不可以匿名访问 -->
				<!-- /** = authc -->
				<!-- /*/* = authc -->
				<!-- /** = authc所有url都不可以匿名访问 必须放到最后面 -->
				/** = authc
			</value>
		</property>
	</bean>
</beans>

我们这里选择的算法呢还是MD5算法,加"盐",并散列两次,之前我们是通过shiro.ini文件将用户信息写死,并且将Credential凭证的加密写在Java程序里,但这违背了Spring的IoC/DI的理念,因此我们选择将这些需要new对象的部分配置在xml文件中,这样项目在启动之后会由Spring创建对象并放置在IoC容器中,我们直接去取就可以了。
这里需要特别注意的一点是,因为本次搭建的是Maven的Web项目,因此我们使用的SecurityManager是DefaultWebSecurityManager,不再是之前的DefaultSecurityManager了,注意不要写错了哦。
另外还有一个知识点就是filterChainDefinitions过滤器链,他是最初步的对url进行筛选的"筛子",类似于/login/logout的就是访问路径,后面的参数的意思我这边还是以表的形式列举出来。

过滤器名称 过滤器类 描述
anon org.apache.shiro.web.filter.authc.AnonymousFilter 匿名过滤器
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter 如果继续操作,需要做对应的表单验证否则不能通过
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter 基本http验证过滤,如果不通过,跳转屋登录页面
logout org.apache.shiro.web.filter.authc.LogoutFilter 登录退出过滤器
noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter 没有session创建过滤器
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 权限过滤器
port org.apache.shiro.web.filter.authz.PortFilter 端口过滤器,可以设置是否是指定端口如果不是跳转到登录页面
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter http方法过滤器,可以指定如post不能进行访问等
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 角色过滤器,判断当前用户是否指定角色
ssl org.apache.shiro.web.filter.authz.SslFilter 请求需要通过ssl,如果不是跳转回登录页
user org.apache.shiro.web.filter.authc.UserFilter 如果访问一个已知用户,比如记住我功能,走这个过滤器

6)applicationContext.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"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<import resource="classpath:application-dao.xml"/>
	<import resource="classpath:application-service.xml"/>
	<import resource="classpath:application-shiro.xml"/>
</beans>

5)jdbc.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/shiro
username=root
password=password

6)log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

最后就是我们的web.xml的配置,放在最后当然是压轴的!
7)web.xml
这下面的关于shiro集成的配置一个都不可以少,需要注意的一点是shiroFilter的名字要和application-shiro.xml中的过滤器链的名字保证一致!
因为我们需要过滤的内容是经过DispatcherServelt放行的请求,因此这里在filter-mapping中配置
<servlet-name>springmvc</servlet-name> 代表你DispatcherServelt放行后的请求都会被本shiroFilter监管!

<?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_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>shiro_ssm_layui</display-name>
  <!-- shiro集成开始 -->
	<!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<!-- 设置true代表由servlet容器控制filter的生命周期 -->
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
		<!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
		<init-param>
			<param-name>targetBeanName</param-name>
			<param-value>shiroFilter</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<servlet-name>springmvc</servlet-name>
	</filter-mapping>
  <!-- shiro集成结束 -->
  <!-- 过滤器 -->
  <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>
  </filter>
  <filter-mapping>
  	<filter-name>EncodingFilter</filter-name>
  	<servlet-name>springmvc</servlet-name>
  </filter-mapping>
  <filter>
  	<filter-name>WebStatFilter</filter-name>
  	<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
  	<!-- 注入过滤的文件样式 -->
  	<init-param>
  		<!-- 注入表达式,排除一些不必要的url,比如.js,/jslib/等等-->
  		<param-name>exclusions</param-name>
  		<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
  	</init-param>
  	<!--  配置profileEnable可监控单个url调用的sql列表 -->
  	<init-param>
		<param-name>profileEnable</param-name>
		<param-value>true</param-value>
	</init-param>
	<!-- cookie监控管理配置 -->
	<init-param>
		<param-name>principalCookieName</param-name>
		<param-value>USER_COOKIE</param-value>
	</init-param>
	<!-- 默认的sessionStatMaxCount是1000个 -->  
	<init-param>
		<param-name>principalSessionName</param-name>
		<param-value>USER_SESSION</param-value>
	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>WebStatFilter</filter-name>
  	<!-- 过滤的servelt是StatViewServlet -->
  	<servlet-name>StatViewServlet</servlet-name>
  </filter-mapping>
  <!-- 监听器 -->
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <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:springmvc.xml</param-value>
  	</init-param>
  	<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>*.action</url-pattern>
  </servlet-mapping>
  <servlet>
	<!-- 引入StatViewServlet,本质上就是一个servlet-->
	<servlet-name>StatViewServlet</servlet-name>
	<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
	<!-- 设置账号 -->
	<init-param>
		<param-name>loginUsername</param-name>
		<param-value>root</param-value>
	</init-param>
	<!-- 设置密码 -->
	<init-param>
		<param-name>loginPassword</param-name>
		<param-value>password</param-value>
	</init-param>
	<!-- 设置白名单 -->
	<init-param>
		<param-name>allow</param-name>
		<!-- <param-value>192.168.1.1,192.168.2.4</param-value> -->	
		<param-value></param-value>
	</init-param>
	<!-- 设置黑名单,注意deny级别高于allow,被deny的地址就算allow了也无法访问 -->
	<init-param>
		<param-name>deny</param-name>
		<param-value></param-value>
	</init-param>
  </servlet>
  <servlet-mapping>
  	<servlet-name>StatViewServlet</servlet-name>
  	<url-pattern>/druid/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

自定义UserRealm的修改及登录控制器的创建

第十五式:创建LoginController
因为之前在springmvc.xml中已经配置过视图解析器InternalResourceViewResolver,所以在这里可以直接返回login,代表返回到login.jsp页面,虽然之前在SpringMVC中已经讲到过多次,这里再稍微带一下。

package com.marco.controller;

import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.marco.utils.ActiveUser;

@Controller
@RequestMapping("login")
public class LoginController {
	
	@RequestMapping("toLogin")
	public String toLogin() {
		return "login";
	}
	
	@RequestMapping("login")
	public String login(String username, String userpwd, Model model, HttpSession session) {
		//封装token
		UsernamePasswordToken token = new UsernamePasswordToken(username, userpwd);
		//获取Subject主体
		Subject subject = SecurityUtils.getSubject();
		// 调用主体的登陆方法
		try {
			subject.login(token);
			System.out.println("登陆成功");
			ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
			//将当前的user对象存放在session作用域中
			session.setAttribute("user", activeUser.getUser());
			return "index";
		} catch (IncorrectCredentialsException e) {
			System.err.println("密码不正确");
			model.addAttribute("error", "密码不正确");
		} catch (UnknownAccountException e) {
			System.err.println("用户名不存在");
			model.addAttribute("error", "用户名不存在");
		}
		return "login";
	}
}

第十六式:修改UserRealm
终于到了我们最为关键的一步啦,修改UserRealm,这个之前我们在Shiro的入门篇已经做过类似的案例了,因此理解起来不会那么困难,Realm本质上就是一个安全验证的领域,或者你可以把它理解成一个结界,它就好比一个法师,当你将数据传入,数据首先会被Subject带进SecurityManager的城堡,然后进入到Realm结界,在这个结界中所有的东西都是保密的,SimpleAuthenticationInfo你可以把它当作是一个送口信的,是一个被传递的加密信息,在底层会被结界师凭证匹配器解析,然后返回最终的结果。

package com.marco.realms;

import java.util.List;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
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 org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.marco.domain.User;
import com.marco.service.PermissionService;
import com.marco.service.RoleService;
import com.marco.service.UserService;
import com.marco.utils.ActiveUser;

public class UserRealm extends AuthorizingRealm{
	@Autowired
	UserService userService;
	@Autowired
	RoleService roleService;
	@Autowired
	PermissionService permissionService;
			
	/**
	 * 处理授权
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//获取当前的principal身份信息(一般是用户名、邮箱或者手机号等等)
		String principal = (String) token.getPrincipal();
		System.out.println("Current principal is " + principal);
		//获取当前的credential凭证信息(一般是密码等等)
		char[] credentials = (char[]) token.getCredentials();
		String credential = new String(credentials);
		System.out.println("Current credential is " + credential);
		System.out.println("###@#####################################################");
		//获取账号信息
		String userName = principal.toString();
		User user = userService.queryUserByUserName(userName);
		if(null != user) {
			//查询用户的角色
			List<String> roles = roleService.queryRolesByUserId(user.getUserid());
			//查询用户的权限
			List<String> permissions = permissionService.queryPermissionByUserId(user.getUserid());
			//封装activeUser
			ActiveUser activeUser = new ActiveUser();
			activeUser.setRoles(roles);
			activeUser.setUser(user);
			activeUser.setPermissions(permissions);
			//组装“盐”
			String salt = user.getUsername() + user.getAddress();
			ByteSource credentialsSalt = new SimpleByteSource(salt.getBytes());
			SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(activeUser, user.getUserpwd(), credentialsSalt, this.getName());
			return authenticationInfo;
		}
		return null;
	}
	
	/**
	 * 处理认证
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		ActiveUser  activeUser = (ActiveUser) principals.getPrimaryPrincipal();
		List<String> permissions = activeUser.getPermissions();//从activeUser中获取permissions
		List<String> roles = activeUser.getRoles();//从activeUser中获取roles
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		if(null != roles && roles.size() > 0) {
			authorizationInfo.addRoles(roles);//添加用户角色
		}
		if(null != permissions && permissions.size() > 0) {
			authorizationInfo.addStringPermissions(permissions);//添加用户权限
		}
		return authorizationInfo;
	}
}

前端View层的创建

终于后台的框架已经构建的差不多啦,接下来就是处理前台的,我们这里简化一下为了测试,深思熟虑之后呢还是选择使用"废铁段位"前台页面
第十七式:创建AppListener监听器
知道我套路的朋友因该清楚这个东西的用途了,主要是为了让前台通过${context}指令获取到我们项目的访问名称

package com.marco.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class AppListener implements ServletContextListener{

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		sce.getServletContext().setAttribute("context", sce.getServletContext().getContextPath());
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		
	}
}

第十八式:创建View层页面
先注意看我们的View层的结构,是不是简单到想哭,毕竟我们后台写的这么幸苦…
在这里插入图片描述
最外层的index.jsp是一个跳转页面,没啥好说的

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<jsp:forward page="login/toLogin.action"></jsp:forward>
</body>
</html>

第二个页面login.jsp登录页面,嗯…也没啥好说的

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户登陆</title>
</head>
<body>
<h1 align="center">用户登陆</h1>
	<h5 style="color: red;" align="center">${error}</h5>
	<form action="${context}/login/login.action" method="post">
		<table align="center" width="50%"  border="1" cellpadding="5" cellspacing="5">
			<tr>
				<td align="right">用户名:</td>
				<td>
					<input type="text" name="username">
				</td>
			</tr> 
			<tr>
				<td align="right">密码:</td>
				<td>
					<input type="password" name="userpwd">
				</td>
			</tr> 
			<tr>
				<td colspan="2">
					<input type="submit" value="提交">
				</td>
			</tr> 
		</table>
	</form>
</body>
</html>

最后再来个废铁版的index主页,大家不要嫌弃!

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>系统首页</title>
</head>
<body>
	系统首页
	<hr>
	<shiro:hasPermission name="user:query">
		<a href="${context}/user/query.action">查询用户</a>
		<br>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:add">
		<a href="${context}/user/add.action">添加用户</a>
		<br>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:update">
		<a href="${context}/user/update.action">修改用户</a>
		<br>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:delete">
		<a href="${context}/user/delete.action">删除用户</a>
		<br>
	</shiro:hasPermission>
	<shiro:hasPermission name="user:export">
		<a href="${context}/user/export.action">导出用户</a>
		<br>
	</shiro:hasPermission>
</body>
</html>

欸?大家发现没有,我在每一个功能上面都添加包围了一个标签<shiro:hasPermission name="user:export">,从字面上翻译hasPermission就是有xxx权限的意思,name里面的内容就是权限的名称,它所代表的意思就是,你有这个权限(例如:user:export),我就把这个按钮给你使用,没有的话,那就bye bye,不给你用。


项目测试

好,整整"降龙十八式"打完!敲的那个累啊… 咱们来测试下吧,运行报错的朋友注意看看配置文件,特别是shiro和SSM集成的application-shiro.xml以及web.xml的配置有没有遗漏或者错误
在这里插入图片描述
输入 http://127.0.0.1:8080/marco/index.jsp 进入到一个非常丑的界面之后,我们来试着登录试试看
在这里插入图片描述
我的账号密码是marco和123456,我们先来输入一个错误的账户试试看
在这里插入图片描述
在输入错误的密码试试看
在这里插入图片描述
再输入正确的账号密码发现也没有问题,细心的朋友会发现我们这里少了一个export功能
在这里插入图片描述
没错,我在数据库中配置marco的角色是1,而1对应的是超级管理员,而超级管理员我只设置了4个功能,证明我们的安全策略是没有问题的。

在这里插入图片描述
在这里插入图片描述

后语

到此为止呢,我们项目的初级篇已经完成了…什么?项目还没有完?
没错…接下来就是我们项目改造阶段,这个改造对后期我们学习分布式非常有帮助,所以呢,大家期待一下吧~

标签:web,Marco,Java,filter,Shiro,import,apache,org,shiro
来源: https://blog.csdn.net/weixin_44698119/article/details/98210164