Struts2 的 logger 是與 log4j2 作整合,同樣是 Apache Project 專案之一。為了瞭解一下與架構 Java 專案時的偵錯機制,所以花了半天的時間來實作。

Maven 對 log4j2 相依性

    <properties>
        <struts2.version>2.3.24.1</struts2.version>
        <log4j2.version>2.2</log4j2.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

 

 log4j2.xml (在 src/main/resources 目錄下)

<?xml version="1.0" encoding="UTF-8"?>

<!-- 優先等級: FATAL > ERROR > WARN >INFO > DEBUG -->
<Configuration>
    <properties>  
        <property name="LOG_HOME">/log/mis</property>
        <property name="FILE_NAME">mis</property>    
    </properties>  
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
        <File name="FILE" fileName="${LOG_HOME}/logfile_fileMode.log" append="true">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </File>
        <RollingRandomAccessFile name="MIS_PROJECT"
            fileName="${LOG_HOME}/${FILE_NAME}.log"
            filePattern="${LOG_HOME}/$${date:yyyy-MM}/${FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz">
            
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" />
            <Policies>
                <TimeBasedTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20" />
        </RollingRandomAccessFile>
        
    </Appenders>
    <Loggers>
        <Logger name="com.opensymphony.xwork2" level="info"/>
        <Logger name="org.apache.struts2" level="info"/>
        
        <Logger name="com.mis.demo" level="DEBUG" additivity="true">
            <AppenderRef ref="STDOUT"/>
        </Logger>

        <Root level="info">
            <AppenderRef ref="STDOUT"/>                  
        </Root>      
        <Root level="WARN">
            <AppenderRef ref="MIS_PROJECT" />
        </Root>        
    </Loggers>
</Configuration>

參數說明

1. monitorInterval="1800" 指 log4j2 每隔1800秒(半小時),自動監控該設定檔是否有變化,如果變化,則自動根據檔內容重新配置(很不錯的功能!)

2. RollingRandomAccessFile  即表示以檔方式記錄,注意一下 filePattern 的設置,它與 SizeBasedTriggeringPolicy (表示單個檔最大多少容量)結合在一起,非常有用,以這段配置為例,當單個文件達到10M後,會自動將以前的內容,先創建類似 2014-09(年-月)的目錄,然後按 "xxx-年-月-日-序號"命名,打成壓縮包(很體貼的設計,即省了空間,又不丟失以前的日誌資訊)

3. DefaultRolloverStrategy max="20"表示壓縮包,最多保留20個

4. 定義了一個 <Logger name="com.mis.demo" level="DEBUG" additivity="true"> ,使用 Console 方式來觀察日誌,additivity="true" 這裡注意一下,因為下面還有一個root logger,任何其它的logger最終都相當於繼承自root logger。

所以<Root level="WARN"> 這個 root logger中,記錄了 WARN 以上級別的日誌,會寫入日誌 mis.log 檔案內;當 <Logger name="com.mis.demo" level="DEBUG" additivity="true"> 有 DEBUG 以上級別的日誌時,也會寫入檔案日誌 mis.log 檔案內。。如果把additivity="true" 中的true,改成false,root logger就不會再起作用,即只會控制台輸出,日誌不會記錄在檔案中。

 

程式 Log4j2Example.java

package com.mis.demo;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Example {

    private static final Logger LOG = LogManager.getLogger(Log4j2Example.class.getName());
    public static void main(String[] args) {
        LOG.debug("This will be printed on debug");        
        LOG.info("This will be printed on info");
        LOG.warn("This will be printed on warn");
        LOG.error("This will be printed on error");
        LOG.fatal("This will be printed on fatal");

        LOG.info("Appending string: {}.", "Hello, World");

    }

}

 

 輸出的格式內容

2016-03-11 10:43:52,260 DEBUG [main] demo.Log4j2Example (Log4j2Example.java:9) - This will be printed on debug
2016-03-11 10:43:52,261 INFO  [main] demo.Log4j2Example (Log4j2Example.java:10) - This will be printed on info
2016-03-11 10:43:52,262 WARN  [main] demo.Log4j2Example (Log4j2Example.java:11) - This will be printed on warn
2016-03-11 10:43:52,262 ERROR [main] demo.Log4j2Example (Log4j2Example.java:12) - This will be printed on error
2016-03-11 10:43:52,262 FATAL [main] demo.Log4j2Example (Log4j2Example.java:13) - This will be printed on fatal
2016-03-11 10:43:52,263 INFO  [main] demo.Log4j2Example (Log4j2Example.java:15) - Appending string: Hello, World.

 

 參考:

http://www.cnblogs.com/yjmyzz/p/3988114.html

http://blog.csdn.net/jiangguilong2000/article/details/11397557

http://memorynotfound.com/log4j2-with-log4j2-xml-configuration-example/

https://logging.apache.org/log4j/2.x/manual/configuration.html

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

當 struts2 加入 struts2-spring-plugin 的 JAR 檔後,執行 JUnit 或 Maven build 時發生 

SEVERE:   [50:59.081] ********** FATAL ERROR STARTING UP STRUTS-SPRING INTEGRATION **********
Looks like the Spring listener was not configured for your web app!
Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext.
You might need to add the following to web.xml:
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
SEVERE:   [50:59.089] Dispatcher initialization failed

 

這時候 JUnit 程式的 extends 要由 StrutsTestCase 變為 StrutsSpringTestCase ,這樣才不會出錯。程式碼如下

package com.mis.example;

import com.opensymphony.xwork2.ActionSupport;

import org.apache.struts2.StrutsSpringTestCase;
import org.apache.struts2.StrutsTestCase;

//public class HelloWorldTest extends StrutsTestCase{
public class HelloWorldTest extends StrutsSpringTestCase {

    public void testHelloWorld() throws Exception {
        HelloWorld hello_world = new HelloWorld();
        String result = hello_world.execute();
        assertTrue("Expected a success result!",
                ActionSupport.SUCCESS.equals(result));
        assertTrue("Expected the default message!",
                hello_world.getText(HelloWorld.MESSAGE).equals(hello_world.getMessage()));
    }
}

 

參考:

http://blog.csdn.net/zj133520/article/details/12620763

http://kang36897.blog.163.com/blog/static/170473732010710101238126/

http://openhome.cc/Gossip/JUnit/

http://linuschien.blogspot.tw/2013/01/unit-test-to-struts2-action-with-spring.html

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

上次介紹 Spring Quartz Job Schedule Simple Example 工作排程器 ,現在再來使用 Spring 原生的 Task Execution and Scheduling,首先來瞭解一下 @Scheduled annotation 的意思

This annotation is used for task scheduling. The trigger information needs to be provided along with this annotation. You can use the properties fixedDelay/fixedRate/cron to provide the triggering information.

1. fixedRate: makes Spring run the task on periodic intervals even if the last invocation may be still running. 固定時間執行,不管上一次是否結束
2. fixedDelay: specifically controls the next execution time when the last execution finishes. 上一次執行結束後,再依設定的固定時間執行
3. cron: is a feature originating from Unix cron utility and has various options based on your requirements. BJ4(就不解釋了)

 

方法 1) Task scheduling using fixed delay attribute in @Scheduled annotation

Step 01: 設定 applicationContext.xml,將 task 選取

applicationContext  

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.2.xsd
        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/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- Spring Task using Annotation-->
    <task:annotation-driven/>
    <bean id="SpringTask-Annotation" class="com.mis.demo.SpringTaskAnnotationDemo"/>
    

</beans>   

 

Step 02: 建立 SpringTaskAnnotationDemo.java

package com.mis.demo;

import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
public class SpringTaskAnnotationDemo {
    @Scheduled(fixedDelay = 5000)
    //@Scheduled(fixedRate = 5000)
    public void demoServiceMethod()
    {
        System.out.println("Method executed at every 5 seconds. Current time is :: "+ new Date());
    }
}

這樣就可以運作了,簡單吧 !!

 

方法 2) Task scheduling using cron expression in @Scheduled annotation

Step 01: 在 applicationContext.xml 設定 class 的 task:scheduled 執行方法,所以在 SpringTaskExecutorDemo.java 的執行 method 為 execute。

    <!-- Spring Task Using cron -->
    <bean id="SpringTask-Cron" class="com.mis.demo.SpringTaskExecutorDemo"/>
    <task:scheduled-tasks>
        <task:scheduled ref="SpringTask-Cron" method="execute" cron="*/5 * * * * ?"/>
    </task:scheduled-tasks>

 

Step 02:  建立 SpringTaskExecutorDemo.java

package com.mis.demo;

import java.util.Calendar;


public class SpringTaskExecutorDemo {
    public void execute () {
        System.out.println("SpringTaskExecutorDemo: Run at " + Calendar.getInstance().getTimeInMillis() );
    }
}

 

這樣就可以運作了,也很簡單吧 !!

 

 

 

 

參考:

http://howtodoinjava.com/spring/spring-core/4-ways-to-schedule-tasks-in-spring-3-scheduled-example/

http://jimwayne.blogspot.tw/2014/04/spring-framework.html

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

MIS 發表在 痞客邦 留言(0) 人氣()

配置:

Maven: pom.xml

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.2</version>
</dependency>

 

Quartz是一個任務進度管理器,以下做簡單的配置

Step 1. 编寫工作(Job class):SpringQuartzJobDemo.java ,需要繼承 spring 中的 QuartzJobBean,因為 QuartzJobBean 類實現了 Job 接口

package com.mis.demo;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class SpringQuartzJobDemo extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Business code ..");

    }

}

 

Step 2. Quartz 定時任務,由 Spring 依賴注入配置方法

<?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:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-4.2.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- Spring Quartz -->
    <!--集成方式:MethodInvokingJobDetailFactoryBean,並且任務類別,是需要繼承QuartzJobBean-->
    <!--定義jobDetail-->
    <bean name="schedulingJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.mis.demo.SpringQuartzJobDemo"/>
        <property name="durability" value="true" />        
    </bean>
 
    <!--定義Trigger觸發器: cronExpression 表達式的格式:秒 分 時 日 月 周 年(可選)-->
    <bean id="triggerJob" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="schedulingJob"/>
        <property name="cronExpression" value="*/5 * * * * ?" />
    </bean>
 
        <!--定義核心調度器-->
    <bean id="scheduleController" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="true">
        <property name="schedulerName" value="monitorScheduler"/>
        <property name="triggers">
            <list>            
                 <ref bean="triggerJob"/>
            </list>                
        </property>
    </bean>

    
</beans>

 

Step 3. 完成設定之後,只要啟動Spring並讀取定義檔完成後,排程任務就會進行,

撰寫一個簡單的任務啟動類別:SpringQuartzJobExcute.java

package com.mis.demo;
import org.quartz.SchedulerException;
import org.quartz.impl.StdScheduler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class SpringQuartzJobExcute {

    private static ApplicationContext APP_CONTEXT;
    
    public static void main(String[] args) throws SchedulerException {
        APP_CONTEXT = new FileSystemXmlApplicationContext("/src/main/resources/spring-demo-cfg.xml");
        
        System.out.println("Start - ScheduleController");
 
        getScheduleController().start();

    }

    /**
     * get StdScheduler
     *
     * @return StdScheduler
     */
    public static StdScheduler getScheduleController() {
        StdScheduler bean = null;
        bean = (StdScheduler) APP_CONTEXT.getBean("scheduleController", StdScheduler.class);
        return bean;
    }

}

 

 

Cron表達式的格式:秒 分 時 日 月 周 年(可選)。

字段名                 允許的值                        允許的特殊字符

秒                         0-59                               , – * /

分                         0-59                               , – * /

小時                      0-23                               , – * /

日                         1-31                               , – * ? / L W C

月                         1-12 or JAN-DEC            , – * /

周幾                      1-7 or SUN-SAT             , – * ? / L C #

年 (可選字段)     empty, 1970-2099             , – * /

 “?”字符:表示不確定的值

 “,”字符:指定數個值

“-”字符:指定一個值的範圍

“/”字符:指定一個值的增加幅度。n/m表示從n開始,每次增加m

“L”字符:用在日表示一個月中的最後一天,用在周表示該月最後一個星期X

“W”字符:指定離给定日期最近的工作日(周一到周五)

“#”字符:表示該月第幾個周X。6#3表示該月第3個周五

 

Cron表達式範例:

每隔5秒執行一次:*/5 * * * * ?

每隔1分鐘執行一次:0 */1 * * * ?

每天23點執行一次:0 0 23 * * ?

每天淩晨1點執行一次:0 0 1 * * ?

每月1號淩晨1點執行一次:0 0 1 1 * ?

每月最後一天23點執行一次:0 0 23 L * ?

每周星期天淩晨1點實行一次:0 0 1 ? * L

在26分、29分、33分執行一次:0 26,29,33 * * * ?

每天的0點、13點、18點、21點都執行一次:0 0 0,13,18,21 * * ?

 

參考資料: http://quartz-scheduler.org/documentation

 

參考:

http://wp.mlab.tw/?p=1701

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

http://quartz-scheduler.org/overview/quick-start

 

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

看完 Spring Data JPA 基本篇 與 Spring Data JPA 進階篇 之後,再來看一下 Spring Data JPA 框架,它主要針對的就是 Spring 唯一沒有簡化到的業務邏輯代碼。接下來我們針對前面的例子進行改造,讓 Spring Data JPA 來幫助我們完成業務邏輯。在著手寫代碼之前,開發者需要先 下載Spring Data JPA 的發佈包(需要同時下載 Spring Data Commons 和 Spring Data JPA 兩個發佈包,Commons 是 Spring Data 的公共基礎包),並把相關的依賴 JAR 檔加入到 CLASSPATH 中。

 

Step 01: DAO Interface: PersonSpringDataJPADao.java

package com.mis.demos.dao;

import org.springframework.data.repository.Repository;

import com.mis.demos.model.Person;
public interface PersonSpringDataJPADao extends Repository<Person, Integer> {

    public Person save(Person person);
    
}

expends Repository 時,需要宣告 public Person save(Person person); 作為儲存的方法。expends CrudRepository 或 JpaRepository 時,則不需宣告,如下:

package com.mis.demos.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.mis.demos.model.Person;
@Repository("PersonSpringDataJPADao")
public interface PersonSpringDataJPADao extends JpaRepository<Person, Integer> {

    
}

不要懷疑,就只是宣告一個 Interface 而已,而且是空的;至於加入 @Repository("PersonSpringDataJPADao") 只是讓 Control 層也能直接引用。

Step 02: Service: PersonSpringDataJPAService.java

package com.mis.demos.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mis.demos.dao.PersonSpringDataJPADao;
import com.mis.demos.model.Person;

@Service("PersonSpringDataJPAService")
public class PersonSpringDataJPAService {

    @Autowired
    PersonSpringDataJPADao personSpringDataJPADao;
    
    public Person saveAccount(Person person){
        return personSpringDataJPADao.save(person);
    }
    public Person findPersonById(Integer id){
        return personSpringDataJPADao.findOne(id);
    }
}

 

Step 03:  spring-demo-cfg.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:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-4.2.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 聲明Spring要管理的範圍
    只要搜尋 service 一個 package 就可以了,model 交給 EntityManager 負責,dao 交給 Spring Data JPA 負責。-->
    <context:component-scan base-package="com.mis" />    

    <tx:annotation-driven transaction-manager="transactionManager" />
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <bean id="entityManagerFactory"    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">        
    </bean>

    <!--  Spring Data JPA 的設定 -->
    <jpa:repositories base-package="com.mis.demos.dao"/>
    
</beans>

 

Step 04: 新增測試

package com.mis.demos;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mis.demos.dao.PersonDao;
import com.mis.demos.dao.PersonSpringDataDao;
import com.mis.demos.dao.PersonSpringDataJPADao;
import com.mis.demos.model.Person;
import com.mis.demos.services.PersonPU;
import com.mis.demos.services.PersonService;
import com.mis.demos.services.PersonSpringDataJPAService;
import com.mis.demos.services.PersonSpringDataService;
import com.mis.demos.services.PersonSpringDataServiceImpl;
public class SimpleSpringJpaDemo {

    public static void main(String[] args) {

        doSpringDataJPASave();
        
    }
   
    public static void doSpringDataJPASave(){
        Person person = new Person();
        Person who = new Person();
        List<Person> allPerson= new ArrayList<Person>();

        //person.setId(1);
        person.setFirstName("polin-99-3");
        person.setLastName("wei-99-2");
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-demo-cfg.xml");
        // 透過 Service
        PersonSpringDataJPAService personSpringDataJPAService = ctx.getBean("PersonSpringDataJPAService",PersonSpringDataJPAService.class);
        personSpringDataJPAService.saveAccount(person);
        who = personSpringDataJPAService.findPersonById(person.getId());
        System.out.println(who.getFirstName());
        //直接呼叫 DAO
        PersonSpringDataJPADao personSpringDataJPADao = ctx.getBean("PersonSpringDataJPADao",PersonSpringDataJPADao.class);
        //personSpringDataJPADao.delete(who.getId());
        allPerson = personSpringDataJPADao.findAll();
        for (Person person2 : allPerson) {
            System.out.println(person2.getId());
        }
        ctx.close();
    }

}

 

真的可以寫入耶,真是太棒了.

 

Step 05: 在 DAO: PersonSpringDataJPADao.java,使用 @Query 提供自訂查詢語句示例

package com.mis.demos.dao;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import com.mis.demos.model.Person;
@Repository("PersonSpringDataJPADao")
public interface PersonSpringDataJPADao extends JpaRepository<Person, Integer> {

    //使用 @Query 提供自訂查詢語句示例
    @Query("select p from Person p where p.firstName = ?1")
    public List<Person> findByFirstName(String FirstName);
}

 

Step 06: 查詢測試

package com.mis.demos;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mis.demos.dao.PersonDao;
import com.mis.demos.dao.PersonSpringDataDao;
import com.mis.demos.dao.PersonSpringDataJPADao;
import com.mis.demos.model.Person;
import com.mis.demos.services.PersonPU;
import com.mis.demos.services.PersonService;
import com.mis.demos.services.PersonSpringDataJPAService;
import com.mis.demos.services.PersonSpringDataService;
import com.mis.demos.services.PersonSpringDataServiceImpl;
public class SimpleSpringJpaDemo {

    public static void main(String[] args) { 

        doSpringDataJPASave();
        
    }

    
    public static void doSpringDataJPASave(){
        Person person = new Person();
        Person who = new Person();
        List<Person> allPerson= new ArrayList<Person>();

        //person.setId(1);
        person.setFirstName("polin-99-3");
        person.setLastName("wei-99-2");
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-demo-cfg.xml");
        PersonSpringDataJPAService personSpringDataJPAService = ctx.getBean("PersonSpringDataJPAService",PersonSpringDataJPAService.class);
        personSpringDataJPAService.saveAccount(person);
        who = personSpringDataJPAService.findPersonById(person.getId());
        System.out.println(who.getFirstName());
        PersonSpringDataJPADao personSpringDataJPADao = ctx.getBean("PersonSpringDataJPADao",PersonSpringDataJPADao.class);
        //personSpringDataJPADao.delete(who.getId());
        allPerson = personSpringDataJPADao.findAll();
        for (Person person2 : allPerson) {
            System.out.println(person2.getId());
        }
        allPerson = personSpringDataJPADao.findByFirstName("polin-99-3");
        for (Person person2 : allPerson) {
            System.out.println(person2.getId());
        }
        ctx.close();
    }

}

 

 本文主要介紹了 Spring Data JPA 的使用,以及它與 Spring 框架的無縫集成。Spring Data JPA 其實並不依賴於 Spring 框架。

參考:

http://spring.io/blog/2011/02/10/getting-started-with-spring-data-jpa/

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Spring Data JPA 基本篇 談到 JPA 的基本作業,現在加入 Spring 的注入(Dependency Injection)來看,Spring 簡化程式碼有多少.

Step 01: DAO Interface: PersonSpringDataDao.java

package com.mis.demos.dao;

import com.mis.demos.model.Person;

public interface PersonSpringDataDao {

    public Person Save(Person person);
    
}

 

Step 02: DAO Implement: PersonSpringDataDaoImpl.java

package com.mis.demos.dao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.mis.demos.model.Person;
@Repository("PersonSpringDataDao")
public class PersonSpringDataDaoImpl implements PersonSpringDataDao {

     @PersistenceContext
     private EntityManager em;
    
    @Transactional
    public Person Save(Person person) {
        if (person.getId()==null)
            em.persist(person);
        else
            em.merge(person);
        return person;
    }

}

 

Step 03: Service Interface: PersonSpringDataService.java

package com.mis.demos.services;

import com.mis.demos.model.Person;

public interface PersonSpringDataService {

    public Person saveAccount(Person person);
}

 

Step 04: Service implement: PersonSpringDataServiceImpl.java , Spring 完成依賴注入,因此不再需要使用 new 操作符創建 PersonSpringDataDaoImpl 物件了

package com.mis.demos.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mis.demos.dao.PersonSpringDataDao;
import com.mis.demos.dao.PersonSpringDataDaoImpl;
import com.mis.demos.model.Person;

@Service("PersonSpringDataService")
public class PersonSpringDataServiceImpl implements PersonSpringDataService {

    //private PersonSpringDataDao personSpringDataDao = new PersonSpringDataDaoImpl();
    @Autowired
    private PersonSpringDataDao personSpringDataDao;
    @Transactional
    public Person saveAccount(Person person) {
        
        return personSpringDataDao.Save(person);
    }

}

 

Step 05:  建立 Spring 設定檔: spring-demo-cfg.xml ,它會去參考 META-INF\persistence.xml 裡的 persistence-unit ,只有一個 PU 時, 則為預設的 data source

<?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:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-4.2.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 聲明Spring要管理的範圍 -->
    <context:component-scan base-package="com.mis" />       

    <tx:annotation-driven transaction-manager="transactionManager" />
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <bean id="entityManagerFactory"    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">        
    </bean>

</beans>

 

Step 06: 測試

package com.mis.demos;

import javax.annotation.Resource;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mis.demos.dao.PersonDao;
import com.mis.demos.dao.PersonSpringDataDao;
import com.mis.demos.model.Person;
import com.mis.demos.services.PersonPU;
import com.mis.demos.services.PersonService;
import com.mis.demos.services.PersonSpringDataService;
import com.mis.demos.services.PersonSpringDataServiceImpl;
public class SimpleSpringJpaDemo {

    public static void main(String[] args) {        

        doSpringDataJPASave();
    }
   
   
    public static void doSpringDataJPASave(){
        Person person = new Person();

        person.setId(1);
        person.setFirstName("polin-9-12");
        person.setLastName("wei-9-12");
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-demo-cfg.xml");
        //PersonSpringDataDao personSpringDataDao = ctx.getBean("PersonSpringDataDao",PersonSpringDataDao.class);
        //personSpringDataDao.Save(person);
        // 注意這裡是取得 Service Interface : PersonSpringDataService.java , 不是實作 PersonSpringDataServiceImpl.java
        PersonSpringDataService personSpringDataService = ctx.getBean("PersonSpringDataService",PersonSpringDataService.class);
        personSpringDataService.saveAccount(person);
        ctx.close();
        
    }

}

 

由此可知,通過與 Spring Data JPA 基本篇 程式碼的對比,程式重構前後的代碼,可以發現 Spring 對 JPA 的簡化已經非常出色了,可以大致總結一下 Spring 框架對 JPA 提供的支援主要體現在如下幾個方面:


•    首先,它使得 JPA 配置變得更加靈活。JPA 規範要求,設定檔必須命名為 persistence.xml,並存在於類路徑下的 META-INF 目錄中。該檔通常包含了初始化 JPA 引擎所需的全部資訊。Spring 提供的 LocalContainerEntityManagerFactoryBean 提供了非常靈活的配置,persistence.xml 中的資訊都可以在此以屬性注入的方式提供。

•    其次,Spring 實現了部分在 EJB 容器環境下才具有的功能,比如對 @PersistenceContext、@PersistenceUnit 的容器注入支援。

•    第三,也是最具意義的,Spring 將 EntityManager 的創建與銷毀、事務管理等代碼抽取出來,並由其統一管理,開發者不需要關心這些,如前面的代碼所示,業務方法中只剩下操作領域物件的代碼,事務管理和 EntityManager 創建、銷毀的代碼都不再需要開發者關心了。

 

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

本文的示例代碼基於 Hibernate EntityManager 開發,程式碼中使用到的都是 JPA 規範提供的Interface / Class,以便瞭解 JPA 基本的概念。整個系統架構如下

jpa-mis  

Step 01 : create mysql table: person

CREATE TABLE `person` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `firstName` varchar(45) NOT NULL,
  `lastName` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

 

 Step 02: 利用 Hibernate Tool 自動建立 Entity model :Person.java

package com.mis.demos.model;
// Generated Jan 20, 2016 10:35:00 AM by Hibernate Tools 4.3.1

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Person generated by hbm2java
 */
@Entity
@Table(name = "person", catalog = "spring")
public class Person implements java.io.Serializable {

    private Integer id;
    private String firstName;
    private String lastName;

    public Person() {
    }

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "id", unique = true, nullable = false)
    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "firstName", nullable = false, length = 45)
    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @Column(name = "lastName", nullable = false, length = 45)
    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}

 

Step 03: 直接用 Service 去存取 table ,不建立 DAO (Data Access Object),正常來說,是應該要先建立 DAO 的,我有點偷懶...:

package com.mis.demos.services;


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import com.mis.demos.model.Person;
/**
 * 沒有透過 DAO 操作 CRUD
 * @author polin.wei
 *
 */
public class PersonPU {

    private EntityManager em;
    private EntityManagerFactory emf;
    
    
    public void clientSave(Person person){        
        emf = Persistence.createEntityManagerFactory("mysqlLocalPU");
        em = emf.createEntityManager();        
        if (person.getId()==null){
            // new
            em.getTransaction().begin();
            em.persist(person);
            em.getTransaction().commit();
        } else {
            // update
            em.getTransaction().begin();
            em.merge(person);
            em.getTransaction().commit();
        }
        em.close();
        emf.close();
    }
}

 

Step 04: 建立 src\main\resources\META-INF\persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    version="2.0">
    <persistence-unit name="mysqlLocalPU"
        transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver" />
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/spring" />
            <property name="hibernate.connection.username" value="root" />
            <property name="hibernate.connection.password" value="root" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.use_sql_comments" value="false" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>

</persistence>

 

Step 05: 測試

package com.mis.demos;

import javax.annotation.Resource;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mis.demos.dao.PersonDao;
import com.mis.demos.dao.PersonSpringDataDao;
import com.mis.demos.model.Person;
import com.mis.demos.services.PersonPU;
import com.mis.demos.services.PersonService;
import com.mis.demos.services.PersonSpringDataService;
import com.mis.demos.services.PersonSpringDataServiceImpl;
public class SimpleSpringJpaDemo {

    public static void main(String[] args) {
        
        doPersistenceSave();

    }

    public static void doPersistenceSave(){
        Person person = new Person();
        // 利用 ID 是否有給值來作 save & update 的判斷
        person.setId(2);
        person.setFirstName("polin-2-6");
        person.setLastName("wei-2-6");

        new PersonPU().clientSave(person);        
    }
 

}

 

 

從 Spring + Hibernate 到 Spring Data JPA

http://cw1057.blogspot.tw/2013/12/more-in-spring-data-jpa-150-m1.html

https://struts.apache.org/docs/struts-2-spring-2-jpa-ajax.html#Struts2+Spring2+JPA+AJAX-Themavenway

https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/

http://www.mastertheboss.com/jboss-frameworks/hibernate-jpa/jpa-configuration/how-to-use-multiple-database-in-persistencexml

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 Customize Theme & Freemarker Template 客制佈景與模板 說明了Struts2 的 tags 是可以自行客制成自已想要的佈景,現在來說明如何使用 FreeMarker 來制作 Struts2 屬於自已建作的 tag libs.

工具:

eclipse : Version: Mars Release (4.5.0) Build id: 20150621-1200

pom.xml:

struts2-core: 2.5.8

struts-annotations: 1.0.5 (不可以用 1.0.6 會出現 tlibVersion Missing 的錯誤)

commons-logging: 1.2

jsp-api : 2.2

javax.servlet-api : 4.0.1

 

Step 01:  建立一個空的 maven project

tag_01

tag_02

 

Step 02: 建立客制的 class: HtmlTag.java 在 package com.easyui.struts2.views.jsp.ui 下

package com.easyui.struts2.views.jsp.ui;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.components.Component;
import org.apache.struts2.views.jsp.ui.AbstractClosingTag;

import com.easyui.struts2.components.Html;
import com.opensymphony.xwork2.util.ValueStack;

public class HtmlTag extends AbstractClosingTag {

    @Override
    public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
        
        return new Html(stack, req, res);
    }

}

 

Step 03 : 建立客制的 class: Html.java 在 package com.easyui.struts2.components , 此檔主要是要產生 .tld 的標籤描述檔, 以及告訴 freemarker 要讀取那一個 ftl , 此範例是要有 html.ftl 與 html-close.ftl 這兩個檔案.

package com.easyui.struts2.components;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.components.ClosingUIBean;
import org.apache.struts2.views.annotations.StrutsTag;

import com.opensymphony.xwork2.util.ValueStack;

@StrutsTag(
        name="html",
        tldTagClass="com.easyui.struts2.views.jsp.ui.HtmlTag",
        description="建立一個空的 HTML 結構",
        allowDynamicAttributes=true)
public class Html extends ClosingUIBean {

    public Html(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
        super(stack, request, response);
        
    }

    @Override
    public String getDefaultOpenTemplate() {        
        return "html";
    }

    @Override
    protected String getDefaultTemplate() {        
        return "html-close";
    }

}

註:

1. 在 pom.xml 中需加入 struts-annotations: 1.0.5 才可以使用 annotations 描述

2. @StrutsTag: annotation for marking a Struts tag
3. @StrutsTagAttribute: annotation for marking an attribute of a Struts tag

 

Step 04: 建立此 tags (標籤) 的 templates & theme

1. 建立 package: template.easyui 並撰寫 html.ftl 與 html-close.ftl

2. 建立 空的 package: template.easyui.html 用來存放 Tobago plugin 自動產生的相關樣版檔案

html.ftl 檔

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>${parameters.title}</title>  
</head>
<body>

 

html-close.ftl 檔


</body>
</html>

 

Step 05: 用 Tobago plugin  建立 TLD file 及使用 Maven 產生這個 taglib 的 jar 檔

請看附註二

 

Step 06: 佈署 (Deploy taglib in your Web application) , 將這個 taglib 的 jar 檔放在 WEB-INF/lib 下

記得要在 struts.xml 裡加入 <constant name="struts.ui.theme" value="easyui"/> , 這樣才會去讀取 JAR 檔 template.easyui 裡的 ftl 檔案

 

Step 07: JSP 裡使用客製的 tag libs

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib prefix="i" uri="/esayui-tags" %>

<i:html title="Basic Layout - jQuery EasyUI Demo">

hi easyui-tags

    <s:form action="Login">
        <s:textfield key="username"/>
        <s:password key="password" />
        <s:submit/>
    </s:form>


</i:html>

 

附註:

一、 Struts2 taglibs Introduction

Few words about the elements of the Struts2 UI component framework should help to understand better the scenario.

JSP Tag: implementation of the JSP tag (e.g TextFieldTag). Notice Struts2 has also Velocity and FreeMarker tags

UI Component: actual implementation of the behavior of the component (e.g TextField)

Template: FreeMarker template which renders the html markup (e.g. <input type=”text”….)

Theme: collection of templates (e.g. simple or ajax)

 

二、整個專案結構如下

tag_03  

註:

1. 在 pom.xml 中需加入 tobago 描述, 才會自動產生目錄: src/main/resources/META-INF 的 easyui-tags.tld 描述檔及 package: template.easyui.html 裡的 html.html

2. 目前 的編譯器 complier 需用 JDK 1.7.x 版才會成功,   JDK1.8.x 會無法產生 easyui-tags.tld 描述檔 及相關的樣版檔

tag_04  

3. Tobago plugin 在 pom.xml 的設定如下:

<plugin>
    <groupId>org.apache.myfaces.tobago</groupId>
    <artifactId>maven-apt-plugin</artifactId>                            
    <configuration>
        <A>
                   uri=/esayui-tags,tlibVersion=${project.version},jspVersion=2.0,shortName=easyui,displayName="EasyUI Tags",
                   outFile=${basedir}/src/main/resources/META-INF/${project.artifactId}.tld,
                   description="EasyUI Tags",
                   outTemplatesDir=${basedir}/src/main/java/template/easyui/html                
        </A>
        <resourceTargetPath>target</resourceTargetPath>
        <fork>false</fork>
        <force>true</force>
        <nocompile>true</nocompile>
        <showWarnings>true</showWarnings>
        <factory>
            org.apache.struts.annotations.taglib.apt.TLDAnnotationProcessorFactory
        </factory>
        <target>1.5</target>
        <includes>
            <include>**/*.java</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <phase>compile</phase>
            <goals>
                <goal>execute</goal>
            </goals>
        </execution>
    </executions>
</plugin>

 


 三、 完整的 pom.xml 檔

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.gu.apps</groupId>
  <artifactId>easyui-tags</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>easyui-tags</name>
  <dependencies>
      <dependency>
          <groupId>org.apache.struts</groupId>
          <artifactId>struts2-core</artifactId>
          <version>2.3.24.1</version>
      </dependency>
      <dependency>
          <groupId>org.apache.struts</groupId>
          <artifactId>struts-annotations</artifactId>
          <version>1.0.5</version>
      </dependency>
      <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
      </dependency>
      <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.1</version>
      </dependency>
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
      </dependency>
  </dependencies>
  <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <build>
      <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <encoding>UTF-8</encoding>
                <source>1.5</source>
                <target>1.5</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.myfaces.tobago</groupId>
            <artifactId>maven-apt-plugin</artifactId>                            
            <configuration>
                <A>
                       uri=/esayui-tags,tlibVersion=${project.version},jspVersion=2.0,shortName=easyui,displayName="EasyUI Tags",
                       outFile=${basedir}/src/main/resources/META-INF/${project.artifactId}.tld,
                       description="EasyUI Tags",
                       outTemplatesDir=${basedir}/src/main/java/template/easyui/html                
                </A>
                <resourceTargetPath>target</resourceTargetPath>
                <fork>false</fork>
                <force>true</force>
                <nocompile>true</nocompile>
                <showWarnings>true</showWarnings>
                <factory>
                    org.apache.struts.annotations.taglib.apt.TLDAnnotationProcessorFactory
                </factory>
                <target>1.5</target>
                <includes>
                    <include>**/*.java</include>
                </includes>
            </configuration>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>execute</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>        
      </plugins>
    <resources>
           <resource>
               <directory>src/main/java</directory>
            <excludes>
                <exclude>**/*.java</exclude>
            </excludes>               
           </resource>
           <resource>
               <directory>src/main/resources</directory>
           </resource>          
       </resources>    
      <finalName>easyui-tags</finalName>
      <defaultGoal>install</defaultGoal>
  </build>
</project>

 

 

參考:

https://bodez.wordpress.com/2009/03/13/customising-struts2-jsp-tags/

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

Struts 2 使用 FreeMarker 來作模板(Template) ,預設的模板是 xhtml (可以解開 struts2-core-2.3.x.x.jar 取得),若要客制佈景(Theme)與模板(Template),需要下列幾個步驟。

預計想要達成的效果有

1. Freemarker Template 中可以使用 Struts 的 tag

2. Customize Theme 客製顏色佈景

 

一、Freemarker Template 中可以使用 Struts 的 tag 實作步驟:

Step 01:  解壓 struts2-core-2.3.x.x.jar 取得 struts-tags.tld 並放在專案(project)的 WEB-INF 下,整個專案目錄如下

struts2-freemarker  

 

Step 02: 修改 web.xml  ,加入 JspSupportServlet 配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="struts_blank" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>Struts Blank-MIS</display-name>

  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>
      org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    </filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

    <servlet>  
        <servlet-name>JspSupportServlet</servlet-name>  
        <servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>  
              <!--配置JspSupportServlet啟動-->  
        <load-on-startup>1</load-on-startup>  
    </servlet>  

  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

Step 03: 在 Freemarker Template 頁面,加入要使明的 taglib,這樣就可以在 template: fmLogin.ftl 中使用 struts2 內建的 tag 標籤,例:<@s.form action="Login.action">

<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] />  
<html>  
<head>  
<title>登錄頁面</title>

<style type="text/css">
    .errorsBg{
        background-color:#fdd;
        color:red;    
        border: 1px solid;
    }
    
    .errorMessage{
        padding:0px 8px;
    }
    
    table{
        border-spacing: 4px;
    }
    td{
        padding:4px;
    }
</style>

</head>  
<body>  
    請輸入用戶名和密碼來登錄<br>  
    <@s.form action="Login.action">  
        <@s.textfield name="username" label="用戶名"/>  
        <@s.textfield name="password" label="密碼"/>  
        <@s.submit value="提交"/>  
    </@s.form>  
</body>  
</html>

 

二、 Customize Theme 客製顏色佈景,客制佈景以 polinwei 為例

Step 01: 建立 package: src/main/java/template/polinwei ,解壓 struts2-core-2.3.x.x.jar 取得 lib\struts2-core-2.3.24.1\template 下目錄 xhtml 的所有檔案放入此 polinwei 目錄下。

struts2-customize-theme  

Step 02: 在 struts.xml 定義要使用的 theme: struts.ui.theme 與 template 目錄: struts.ui.templateDir

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false"/>
    <constant name="struts.devMode" value="true"/>

    <constant name="struts.ui.theme" value="polinwei" />
    <constant name="struts.ui.templateDir" value="template" />   

    <package name="demo" namespace="/demo" extends="struts-default">
        <action name="Login" class="com.demo.FMTestAction">
            <result name="input" type="freemarker">/WEB-INF/demo/fmLogin.ftl</result>
            <result name="success" type="freemarker">/WEB-INF/demo/fmLoginSuccess.ftl</result>
        </action>

    </package>

    <!-- Add addition packages and configuration here. -->

</struts>

 

Step 03: 開始客制佈景

a. Create a new error-message.ftl file to display the error message.

error-message.ftl

<#--
        Only show message if errors are available.
        This will be done if ActionSupport is used.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#if hasFieldErrors>
<#list fieldErrors[parameters.name] as error>
   <span class="errorMessage" errorFor="${parameters.id}">${error?html}</span><#t/>
</#list>
</#if>

 

b. Modify the controlheader.ftl by adding a new “errorsBg” class to “td” tag if errors exists.

controlheader.ftl

<#include "/${parameters.templateDir}/polinwei/controlheader-core.ftl" />
    <td
<#if hasFieldErrors>
    class="errorsBg" <#t/>
</#if>
<#if parameters.align??>
    align="${parameters.align?html}"<#t/>
</#if>
><#t/>

 

c. Modify the controlheader-core.ftl by delete many unnecessary tags and add a new “errorsBg” class to “td” tag if errors exists.

controlheader-core.ftl

<#--
        Only show message if errors are available.
        This will be done if ActionSupport is used.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#--
        if the label position is top,
        then give the label its own row in the table
-->
<tr>

<td class="tdLabel <#t/>
<#--
<#if hasFieldErrors>
errorsBg"<#t/>
</#if>
-->
><#rt/>

<#if parameters.label??>
    <label <#t/>
<#if parameters.id??>
        for="${parameters.id?html}" <#t/>
</#if>
<#if hasFieldErrors>
        class="errorLabel"<#t/>
<#else>
        class="label"<#t/>
</#if>
 ><#t/>

<#if parameters.required?default(false) && parameters.requiredposition?default("right") != 'right'>
    <span class="required">*</span><#t/>
</#if>
${parameters.label?html}<#t/>
<#if parameters.required?default(false) && parameters.requiredposition?default("right") == 'right'>
        <span class="required">*</span><#t/>
</#if>

</label><#t/>
</#if>

</td><#lt/>

 

d. Modify the text.ftl & password.ftl by adding a new template file “error-message.ftl” after the “simple/text.ftl“.

text.ftl

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/text.ftl" />
<#include "/${parameters.templateDir}/polinwei/error-message.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

password.ftl

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<#include "/${parameters.templateDir}/simple/password.ftl" />
<#include "/${parameters.templateDir}/polinwei/error-message.ftl" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

 

 

e. Put the CSS in your view page to format the error message.

<#assign s=JspTaglibs["/WEB-INF/struts-tags.tld"] />  
<html>  
<head>  
<title>登錄頁面</title>

<style type="text/css">
    .errorsBg{
        background-color:#fdd;
        color:red;    
        border: 1px solid;
    }
    
    .errorMessage{
        padding:0px 8px;
    }
    
    table{
        border-spacing: 4px;
    }
    td{
        padding:4px;
    }
</style>

</head>  
<body>  
    請輸入用戶名和密碼來登錄<br>  
    <@s.form action="Login.action">  
        <@s.textfield name="username" label="用戶名"/>  
        <@s.textfield name="password" label="密碼"/>  
        <@s.submit value="提交"/>  
    </@s.form>  
</body>  
</html> 

 

這樣就可以有自已客制的佈景了.

 

參考:

http://www.mkyong.com/struts2/working-with-struts-2-theme-template/

 

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()

上章 JBoss EAP6.x Domain Cluster + mod_cluster-1.2.6 Load Balancer 說完如何建構 EAP 的 cluster 後,再來說一下SSL;現在的網站與使用者間的資料傳輸安全性,大都已逐漸都加入了 SSL ,而企業級有很多網站,這時可以用 Wildcard SSL Certificate 更加有彈性, SSL 憑證的建置步驟大致如下圖:

 

ssl  

 

瞭解建置與使用步驟後,來實作一下,SSL 的憑證以 https://ssl.comodo.com/wildcard-ssl-certificates.p... 為例作示範

Step 01: 產生私鑰 Private Key,指令 openssl genrsa -out server.key 2048 (不對私鑰作密碼保護)

[root@eap-dev jboss]# pwd
/opt/jboss
[root@eap-dev jboss]# rpm -qa | grep openssl
openssl-1.0.1e-42.el7.x86_64
openssl-libs-1.0.1e-42.el7.x86_64

[root@eap-dev jboss]# openssl genrsa -out server.key 2048
Generating RSA private key, 2048 bit long modulus
............+++
...........................+++
e is 65537 (0x10001)

註:若 option 有加入 -des3 則代表要對私鑰作密碼保護如下

[root@eap-dev jboss]# openssl genrsa -des3 -out server.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
.........+++
e is 65537 (0x10001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:

 server-key  

 

Step 02:產生CSR檔,並填入憑證資料,指令 openssl req –new –key server.key –out xxx.CSR

[root@eap-dev jboss]# openssl req -new -key server.key -out EAP-DEV.CSR
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:TW
State or Province Name (full name) []:Taiwan
Locality Name (eg, city) [Default City]:Taichung
Organization Name (eg, company) [Default Company Ltd]:xxxxxx Industrial Corp.
Organizational Unit Name (eg, section) []:Information Technology
Common Name (eg, your name or your server's hostname) []:*.xxxxxx.com
Email Address []:tech.admin@xxxxxx.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

 server-csr  
 

 產生的 CSR 內容,類似下圖

server-csr-content  

 

Step 03: 向CA: comodo.com 申請憑證

 Comodo-ssl-wildcard  

COMODO驗證成功後會收到 yourDomainName.crt 和 yourDomainName.ca-bundle 兩個檔案:

a.  Step 01: 產生私鑰 Private Key 的 server.key 複製到 /etc/ssl/ssl.key/ 

b. 由COMODO拿到的兩個檔案: STAR_yourDomainName.crtSTAR_yourDomainName.ca-bundle 複製到 /etc/ssl/ssl.crt/ 

 

以上三個步驟只要作一次即可,未來只要將這三個檔案: server.keySTAR_yourDomainName.crtSTAR_yourDomainName.ca-bundle 複製到其它主機內即可有 SSL 的保護。

 

Step 04: 修改/opt/jboss/httpd/httpd/conf/httpd.conf,打開註解 Include extra/httpd-ssl.conf,套用ssl 的設定檔。並修改extra/httpd-ssl.conf,修改以下資訊

Listen 443

<VirtualHost _default_:443>

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
SSLEngine on

#   Server Certificate:
SSLCertificateFile "/etc/ssl/ssl.crt/STAR_xxxxxx_com.crt"

#   Server Private Key:
SSLCertificateKeyFile "/etc/ssl/ssl.key/server.key"

#   Server Certificate Chain:
SSLCertificateChainFile "/etc/ssl/ssl.crt/STAR_xxxxxx_com.ca-bundle"

</VirtualHost>

 

Step 04: 修改/opt/jboss/httpd/httpd/conf/httpd.conf,打開註解 Include extra/httpd-vhosts.conf,套用 vhosts 的設定檔。並修改extra/httpd-vhosts.conf,修改以下資訊

<VirtualHost *:80>
    ServerAdmin tech.admin@xxxxxx.com
    DocumentRoot "/opt/jboss/httpd/htdocs/htdocs"
    ServerName eap-dev.xxxxxx.com
    ServerAlias www.eap-dev.xxxxxx.com
    ErrorLog "logs/eap-dev-error_log"
    CustomLog "logs/eap-dev-access_log" common
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin tech.admin@xxxxxx.com
    DocumentRoot "/opt/jboss/httpd/htdocs/htdocs"
    ServerName bpm-dev.xxxxxx.com
    ErrorLog "logs/bpm-dev-error_log"
    CustomLog "logs/bpm-dev-access_log" common
</VirtualHost>

 

以上整個建置就完成了.  

文章標籤

MIS 發表在 痞客邦 留言(0) 人氣()