Sitemesh是由一个基于Web页面布局、装饰及与现存Web应用整合的框架。它能帮助我们在由大量页面工程的项目中创建一致的页面布局和外观,如一致的导航条、一致的banner、一致的版权等。它不仅能处理动态的内容,如JSP、PHP、ASP、CGI等产生的内容,还能处理静态的内容,比如HTML的内容,使得它的内容也符合你的页面结构的要求。甚至它能像include那样将HTML文件作为一个面板的形式嵌入到别的文件中去。所有的这些,都是GOF的Decorator模式的最生动的实现。装饰模式是在不必改变原类文件和使用集成的情况下,动态地扩展一个对象的功能。它能通过创建一个包装对象,也就是装饰来包裹的对象。尽管它是由Java语言来实现的,但是它能与其他Web应用很好的集成。[1] 工作原理编辑 SiteMesh是基于Servlet的filter的,即过滤流。它是通过截取response,并进行装饰后再交付给客户。 其中涉及到两个名词: 装饰页面(decorator page)和 "被装饰页面(Content page)" , 即 SiteMesh通过对Content Page的装饰,最终得到页面布局和外观一致的页面,并返回给客户 sitemesh运行环境需要:servlet, JDK 。 整合spring maven坐标
<dependency>
<groupId>opensymphony</groupId>
<artifactId>sitemesh</artifactId>
<version>2.4.2</version>
</dependency>
由于采用的是过滤器配置 所有在web.xml中配置
<!-- SiteMesh -->
<filter>
<filter-name>sitemeshFilter</filter-name>
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemeshFilter</filter-name>
<url-pattern>/a/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>sitemeshFilter</filter-name>
<url-pattern>/f/*</url-pattern>
</filter-mapping>
需要配置文件 在WEB-INF下创建 decorators.xml 内容:
<?xml version="1.0" encoding="UTF-8"?>
<decorators defaultdir="/WEB-INF/">
<!-- 默认装饰页面, 在需要装饰的页面增加<meta name="decorator" content="blank"/> -->
<decorator name="blank" page="views/layouts/blank.jsp" />
</decorators>
内容多变 这里用最基本的方式
views/layouts/blank.jsp 内容:
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
<%@ taglib prefix="sitemesh"
uri="http://www.opensymphony.com/sitemesh/decorator"%>
<!DOCTYPE html>
<html>
<head>
<title><sitemesh:title /></title>
<%@include file="/WEB-INF/views/include/head_index.jsp"%>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<sitemesh:head />
</head>
<body>
<div id="sb-site">
<sitemesh:body />
<!--引入的头文件,主要登陆信息,提示信息-->
<%@include file="/WEB-INF/views/include/top_blue.jsp"%>
</div>
<div id="back-top">
<a href="#header"><i class="fa fa-chevron-up"></i></a>
<!--引入的尾部文件,主要是公司信息法律途径等-->
<%@include file="/WEB-INF/views/include/footer_blue.jsp"%>
</div>
</body>
</html>
使用方法 在一个新的jsp中 只要指定
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ include file="/WEB-INF/views/include/taglib.jsp" %>
<html>
<head>
<!--这里就是用的sitmesh-->
<meta name="decorator" content="blank"/>
<title>Insert title here</title>
</head>
.......
页面历史 编辑 删除 克隆地址 项目主页:http://www.swiper.com.cn 关于Swiper Swiper 是一款免费以及轻量级的移动设备触控滑块的js框架,使用硬件加速过渡(如果该设备支持的话)。主要使用于移动端的网站、移动web apps,native apps和hybrid apps。主要是为IOS而设计的,同时,在Android、WP8系统也有着良好的用户体验,Swiper从3.0开始不再全面支持PC端。因此,如需在PC上兼容更多的浏览器,可以选择Swiper2.x(甚至支持IE7)。
swiper3.x swiper2.x 移动机制 transform transform或left/top 布局方式 flex或一般布局 一般布局 更新 正在更新 停止更新 最新版本2.7.2 兼容性 部分PC端浏览器,主流移动端浏览器 PC端浏览器,IE7+,部分移动端浏览器
API位置
http://www.swiper.com.cn/api/index.html 引入响应的jquery.js和swiper的js,css文件 一个简单的例子
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link href="http://cdn.bootcss.com/Swiper/3.3.1/css/swiper.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script>
<script src="http://cdn.bootcss.com/Swiper/3.3.1/js/swiper.jquery.min.js"></script>
<script src="http://cdn.bootcss.com/Swiper/3.3.1/js/swiper.min.js"></script>
<style type="text/css">
html,body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #000;
margin: 0;
padding: 0;
}
.swiper-container {
width: 100%;
height: 100%;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
.swiper-pagination-bullet {
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
font-size: 12px;
color: #000;
opacity: 1;
background: rgba(0, 0, 0, 0.2);
}
.swiper-pagination-bullet-active {
color: #fff;
background: #007aff;
}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>被装饰(目标)页面title</title>
</head>
<body>
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide"><img src="static/img/photos(1).jpg"></div>
<div class="swiper-slide"><img src="static/img/photos(2).jpg"></div>
<div class="swiper-slide"><img src="static/img/photos(3).jpg"></div>
<div class="swiper-slide"><img src="static/img/photos(4).jpg"></div>
<div class="swiper-slide"><img src="static/img/photos(5).jpg"></div>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<div class="swiper-scrollbar"></div>
</div>
<script>
var mySwiper = new Swiper('.swiper-container', {
autoplay : 5000,//可选选项,自动滑动
initialSlide :$("img").length,//预加载长度大小
freeMode : true,//默认为false,普通模式:slide滑动时只滑动一格,并自动贴合wrapper,设置为true则变为free模式,slide会根据惯性滑动且不会贴合
effect : 'coverflow',//slide的切换效果,默认为"slide"(位移切换),可设置为"fade"(淡入)"cube"(方块)"coverflow"(3d流)"flip"(3d翻转)。
speed : 1000,//切换速度
autoHeight : true, //高度随内容变化
width : 800,//
autoplay :1000,//过渡延迟时间(单位ms),就是自动滑动时slide的停留时间,参数没有指定的情况下,不生效,
//grabCursor : true,
//parallax : true,//如需要开启视差效果(相对父元素移动),设置为true并在所需要的元素上增加data-swiper-parallax属性。
roundLengths : true, //设定为true将slide的宽和高取整(四舍五入)以防止某些分辨率的屏幕上文字或边界(border)模糊。例如在1440宽度设备上,当你设定slide宽为76%时,则计算出来结果为1094.4,开启后宽度取整数1094
pagination : '.swiper-pagination',//分页器容器的css选择器或HTML标签。分页器等组件可以置于container之外,不同Swiper的组件应该有所区分,如#pagination1,#pagination2
paginationClickable : true,//此参数设置为true时,点击分页器的指示点分页器会控制Swiper切换。
prevButton :'.swiper-button-prev',//前进按钮的css选择器或HTML元素。
nextButton :'.swiper-button-next',//....
scrollbar:'.swiper-scrollbar',//Scrollbar容器的css选择器或HTML元素。
keyboardControl : true,//键盘控制
mousewheelControl : true,//鼠标控制
preloadImages : true,//默认为true,Swiper会强制加载所有图片。
updateOnImagesReady : true,//当所有的内嵌图像(img标签)加载完成后Swiper会重新初始化。使用此选项需要先开启preloadImages: true
loop : true,//循环图片
paginationBulletRender: function (index, className) {//渲染分页器小点。这个参数允许完全自定义分页器的指示点。接受指示点索引和指示点类名作为参数。
return '<span class="' + className + '">' + (index + 1) + '</span>';
},
});
</script>
</body>
</html>
spring-shiro.xml 中
最重要的是:shiroFilter 配置如下
<!-- Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行 Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全接口,这个属性是必须的 -->
<property name="securityManager" ref="securityManager"></property>
<!-- 要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
<property name="loginUrl" value="/toLogin"></property>
<!-- 登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码) -->
<property name="successUrl" value="/" ></property>
<!-- 用户访问未对其授权的资源时,所显示的连接 可以自己定义403页面 权限不足-->
<property name="unauthorizedUrl" value="/403"></property>
<property name="filterChainDefinitions">
<!--这是对权限控制过滤细节-->
<ref bean="shiroFilterChainDefinitions"/>
</property>
</bean>
上面的shiroFilterChainDefinitions 定义如下
<!-- Shiro权限过滤过滤器定义 -->
<!-- Shiro权限过滤过滤器定义 -->
<!-- anon:没有参数,表示可以匿名使用。 -->
<!-- authc:表示需要认证(登录)才能使用,没有参数 -->
<!-- user:没有参数表示必须存在用户,当登入操作时不做检查 -->
<!-- perms:参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。-->
<bean name="shiroFilterChainDefinitions" class="java.lang.String">
<constructor-arg>
<value>
/validateCode = anon
/static/** = anon
/userfiles/** = anon
/login = anon
/toLogin = anon
/logout = logout
/** = user
</value>
</constructor-arg>
</bean>
<!-- 使用Shiro自带的JdbcRealm类 指定密码匹配所需要用到的加密对象 指定存储用户、角色、权限许可的数据源及相关查询语句 -->
<bean id="jdbcRealm" class="com.framework.shs.commom.security.shiro.ShiroDbRealm">
<property name="cacheManager" ref="cacheManager"></property>
<!--密码校验接口-->
<property name="cachingEnabled" value="true"/>
<property name="authenticationCachingEnabled" value="true"/>
<property name="authenticationCacheName" value="authenticationCache"/>
<property name="authorizationCachingEnabled" value="true"/>
<property name="authorizationCacheName" value="authorizationCache"/>
</bean>
如果实现登陆,查询用户和验证,自定义Realm extends AuthorizingRealm
重写
protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken)
验证方法和
AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals)
授权方法
实现细节如下:
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authcToken) throws AuthenticationException {
// UsernamePasswordToken对象用来存放提交的登录信息
//可进行加密
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
String username = token.getUsername();
String password = new String(token.getPassword());
User user = new User();
user.setName(username);
// 查出是否有此用户
user = userService.findByName(token.getUsername());
if (user != null) {
if (user.getPsword().equals(password)) {
// 若存在,将此用户存放到登录认证info中
return new SimpleAuthenticationInfo(username, password,getName());
}
}
throw new UnauthenticatedException();
}
页面历史 编辑 删除 克隆地址 首先配置的是spring核心监听器 web.xml中
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
启动参数 父类 org.springframework.web.context.ContextLoader 属性需要一个启动参数 contextConfigLocation
/**
* Name of servlet context parameter (i.e., {@value}) that can specify the
* config location for the root context, falling back to the implementation's
* default otherwise.
* @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
*/
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
需要 参数 contextConfigLocation
spring加载配置文件
/**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
}
所以我们要在web启动时配置参数 web.xml
通配所有 即:所有启动配置文件都要 spring-xxx.xml样式
<!-- 配置Spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-*.xml</param-value>
</context-param>
接下来配置spring mvc
核心控制器 org.springframework.web.servlet.DispatcherServlet 这是一个servlet,所以配置很简单
<!-- 配置SpringMVC -->
<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>
启动级别设置为1 优先启动并加载 spring-mvc.xml 文件 为了方便编码 我们在设置一个 编码过滤器 统一编码 UTF-8
<!-- 设置字符集 -->
<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>
</filter-mapping>
我们看spring-mvc.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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 开启扫描,注解扫描的包 -->
<context:component-scan base-package="com.framework.shs" />
<!-- 开启注解方案 -->
<mvc:annotation-driven />
<!-- 静态资源访问,方案 -->
<mvc:resources location="/static/" mapping="/static/**" />
<!-- 视图解释类 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views"></property>
<!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- mvc拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截路径-->
<mvc:mapping path="/**" />
<!--不拦截url-->
<mvc:exclude-mapping path="/login"/>
<!--自定义拦截器-->
<bean class="com.framework.shs.commom.system.intercept.LogInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!--有人跟踪@ResponseBody 的实现类发现其默认的编码是 iso-8859-1, 消息转换器 保证影响也是UTF-8编码-->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。