在分享Controller之前,想先提一下會用到View部分技術(如今日的sitemesh3)以及Model部分技術(如hibernate),sitemesh是一種網頁template engine,用到稱作decorator的design pattern,示意圖如下(從官網擷取下來),原理簡單說就是根據需求建立一個或多個網頁template,用在不同的版面上,假設網頁只有一種版型,導覽列在最上面,有個footer,中間是網頁內容,那麼應只需要一個template即可,sitemesh是實作在filter上,所以我們可以攔截不同的網址,設定不同的template,每個回應之網頁將被template "decorate",sitemesh2的時候要作的設定比較多,sitemesh3算是簡化不少,如已無taglib,預設僅剩三種標籤:
<sitemesh:write property="title">
<sitemesh:write property="head">
<sitemesh:write property="body">
這些標籤所對應到的html三個地方,Client所看到的將由新增的網頁中的值所取代,廢話不多說,第一步即是修改pom.xml,新增sitemesh3的dependency。
<dependency>
<groupId>org.sitemesh</groupId>
<artifactId>sitemesh</artifactId>
<version>3.0.0</version>
</dependency>
再來則是需要設定filter mapping,因為已經不用web.xml了,故新增1個class繼承ConfigurableSiteMeshFilter來作sitemesh filter mapping的工作,程式碼如下:
package tw.blogger.springtech.springmvc.config;
import org.sitemesh.builder.SiteMeshFilterBuilder;
import org.sitemesh.config.ConfigurableSiteMeshFilter;
public class SiteMeshFilter extends ConfigurableSiteMeshFilter {
@Override
protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
// TODO Auto-generated method stub
builder.addDecoratorPath("/*", "/WEB-INF/views/layouts/base.jsp");
}
}
設定filter mapping要override applyCustomConfiguration方法,利用builder可以add很多不同的URL mapping以及對應的template(正式說法稱作為decorator),我採用所有的網址都用base.jsp這個template。
沒有web.xml,那麼原本的<filter>要在哪裡設定,我們之前DispatchServlet的Java Config是針對Servlet,filter是發生在servlet之前的,故我們需要另外一個Initizer來新增一個filter並載入SiteMeshFilter,這一個Initizer即為初始化Spring Security的AbstractSecurityWebApplicationInitializer,在進行下一步前,必須先加入Spring Security的dependency如下
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${security.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${security.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${security.version}</version>
<scope>compile</scope>
</dependency>
<properties>
<security.version>3.2.5.RELEASE</security.version>
</properties>
在新增Filter之前,因為Spring Security已有明確定義SpringSecurityFilterChain,故必須先Enable Filter Chain後才能新增新的filter,新增一個class SecurityConfig程式碼如下:
package tw.blogger.springtech.springmvc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.anonymous();
}
}
@EnableWebSecurity即為Enable SpringSecurityFilterChain,必須override configure方法,設定網頁存取權限,http物件就是負責這部分,它是一個builder pattern,目前先呼叫anonymous()使任何人都可以存取網頁。
接著新增一個class繼承AbstractSecurityWebApplicationInitializer,並override afterSpringSecurityFilterChain來並呼叫InsertFilters,把SiteMeshFilter加入,程式碼如下:
package tw.blogger.springtech.springmvc.config;
import javax.servlet.ServletContext;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class WebSecurityConfig extends
AbstractSecurityWebApplicationInitializer {
@Override
protected void afterSpringSecurityFilterChain(ServletContext servletContext) {
// TODO Auto-generated method stub
insertFilters(servletContext, new SiteMeshFilter());
}
}
最後新增base.jsp,UI部份我想試試MetroUI,程式碼如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>I&C Website:<sitemesh:write property='title' /></title>
<link href="<c:url value="/resources/css/metro-bootstrap.css" />"
rel="stylesheet" />
<script src="<c:url value="/resources/js/jquery.min.js" />"></script>
<script src="<c:url value="/resources/js/jquery.mousewheel.js" />"></script>
<script src="<c:url value="/resources/js/jquery.widget.min.js" />"></script>
<script src="<c:url value="/resources/js/main.js" />"></script>
<sitemesh:write property='head' />
<body class="metro">
<nav class="navigation-bar dark">
<nav class="navigation-bar-content container">
<a class="element" href="#"><span class="icon-yelp">DNE I&C Website</span><sup>beta</sup></a> <span class="element-divider"></span>
<ul class="element-menu">
<li><a href="#">DCN Control</a></li>
<li class="divider"></li>
<li><a href="#">IODB Control</a></li>
<li class="divider"></li>
<li><a href="#">FXDB Control</a></li>
<li class="divider"></li>
<li><a href="#">DCT Control</a></li>
<li class="divider"></li>
<li><a href="#">About Us</a></li>
</ul>
</nav>
</nav>
<section>
<sitemesh:write property='body'/>
</section>
index.jsp部分也稍作修改,加入Microsoft的Tile(磚),程式碼改變如下:
<title>Spring MVC Demo</title>
<div class="tile-group double">
<div class="tile-group-title">Core Service</div>
<div class="tile bg-cyan" data-click="transform">
<div class="tile-content icon">
<i class="icon-file"></i>
</div>
<div class="tile-status">
<span class="name">DCN Control</span>
</div>
</div>
<div class="tile bg-darkPink" data-click="transform">
<div class="tile-content icon">
<i class="icon-database"></i>
</div>
<div class="tile-status">
<span class="name">IODB Control</span>
</div>
</div>
<div class="tile bg-amber" data-click="transform">
<div class="tile-content icon">
<i class="icon-cog"></i>
</div>
<div class="tile-status">
<span class="name">FXDB Control</span>
</div>
</div>
<div class="tile bg-crimson" data-click="transform">
<div class="tile-content icon">
<i class="icon-screen"></i>
</div>
<div class="tile-status">
<span class="name">DCT Control</span>
</div>
</div>
</div>
啟動Server,畫面如下:
最後的目標是作CRUD(Create, Read, Update, Delete),M、V、C介紹順序我應該不是那麼重要,用到什麼就跟大家分享什麼吧~
另外MetroUI可以參考這裡,磚裡面的Icon沒有出來不知道為什麼。