2015年4月27日 星期一

(溫故知新) Struts2 簡易練習(查找資料) normal

(溫故知新) Struts2 簡易練習(查找資料) normal

原始碼下載:http://goo.gl/k8WCf9

【開發環境】

Tomcat 7

MySQL

【開發工具】

Intellij IDEA 14

【使用FrameWork】

Struts2

jQuery

【主要畫面】

clip_image002

需求:

1. 按“查詢”秀出結果在下方

2. 需要使用annotation

3. JSP需要使用struts2 tag ex: <s:property value="#myUser.name"/>

4. 查詢時需要檢查在session中是否存在屬性為LOGIN的字串,若是沒有則丟出

錯誤訊息(請使用com.opensymphony.xwork2.interceptor.Interceptor方式實作)

* 請在Struts.xml中Action設定上使用Wildcard Method Selection

【使用到的 MySQL 資料】

-- MySQL 語法
CREATE TABLE IF NOT EXISTS `USER_PROFILE` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`USER_ID` varchar(11) NOT NULL,
`USER_NAME` varchar(10) NOT NULL,
`USER_SEX` varchar(10) NOT NULL,
`USER_PHONE` varchar(10) NOT NULL,
`USER_ADDRESS` varchar(10) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
--INSERT INTO `USER_PROFILE` (`USER_ID`, `USER_NAME`, `USER_SEX`,`USER_PHONE`,`USER_ADDRESS`) VALUES
('2013000001', '張三', 'M','0911120111','台北市士林區'),
('2013000002', '李四', 'M','0911120112','新北市土城區'),
('2013000003', '王五', 'M','0911120113','新北市三重區'),
('2013000004', '陳二', 'F','0911120114','台北市信義區'),
('2013000005', '孫九', 'F','0911120115','台北市中山區');
SELECT * FROM `user_profile`;

web.xml

<!DOCTYPE web-app PUBLIC
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd" >



<web-app>
   <display-name>STRUTS2_normal_1</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>
     <welcome-file-list>
         <welcome-file>/index.jsp</welcome-file>
     </welcome-file-list>

</web-app>

Index.jsp

<%@ page pageEncoding="UTF-8" contentType="text/html; charset=utf-8" %>

<%@ taglib prefix="s" uri="/struts-tags" %>

<html>

<head>
     <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
     <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
     <script>
         $(function(){
            $("#ck_male").click(function(){
                $("#ck_female").prop("checked",false);
            }) ;
             $("#ck_female").click(function(){
                 $("#ck_male").prop("checked",false);
             }) ;
         });
     </script>



</head>

<body>

<h2>Struts2_normal_1</h2>

<!-- 加入警告訊息 -->

<div style="color: red;"><s:actionerror /></div>



<s:form action="queryMethods">
             <s:textfield name="user_profile.userName" label="使用者姓名"/>
             <s:textfield name="user_profile.userPhone" label="使用者電話"/>
             <s:checkbox id="ck_male" name="user_profile.male" label="男"/>
             <s:checkbox id="ck_female" name="user_profile.female" label="女"/>
             <s:submit value="查詢" />

</s:form>

<br>

<s:if test="null!=list&&!list.isEmpty()">
     <hr>
     <s:iterator value="list">
         <table class="table1">
             <tr>
                 <td>編號</td>
                 <td>姓名</td>
                 <td>性別</td>
                 <td>電話</td>
                 <td>地址</td>
             </tr>
             <tr>
                 <td><s:property value="userId" /></td>
                 <td><s:property value="userName" /></td>
                 <td><s:property value="userSex" /></td>
                 <td><s:property value="userPhone" /></td>
                 <td><s:property value="userAddress" /></td>
             </tr>
         </table>
     </s:iterator>

</s:if>

<s:else>
     <hr>
     查無資料

</s:else>



<hr>

<a href="Login">登入</a>

<a href="Logout">登出</a>

</body>

</html>

上面的部分簡單的使用 jQuery 建立 checkbox 檢核機制,當選男的,就會消除女的,反之亦然,另外在整張form 的部份,使用的 struts2 的 s tag,並建立對應的 model 與頁面使用,最後設計兩個連結並導向 Login / Logout 兩個 action,用以模擬登入登出的狀態,在action,將檢核資訊帶入 Session 中。

Model 部分:

USER_PROFILE.java 對應到資料庫的 Table,當中擺入兩個boolean屬性male/female,用以判斷使用者所選的是男性或女性。

package test.Models;



/**
  * Created by Hsu on 2015/4/16.
  */

public class USER_PROFILE {
     private int id;
     private String userId;
     private String userName;
     private String userSex;
     private String userPhone;
     private String userAddress;
     private boolean male;
     private boolean female;


     public boolean isMale() {
         return male;
     }


     public void setMale(boolean male) {
         if(male){
             this.userSex = "M";
         }
         this.male = male;
     }


     public boolean isFemale() {
         return female;
     }


     public void setFemale(boolean female) {
         if(female){
             this.userSex = "F";
         }
         this.female = female;
     }


     public int getId() {
         return id;
     }


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


     public String getUserId() {
         return userId;
     }


     public void setUserId(String userId) {
         this.userId = userId;
     }


     public String getUserName() {
         return userName;
     }


     public void setUserName(String userName) {
         this.userName = userName;
     }


     public String getUserSex() {
         return userSex;
     }


     public void setUserSex(String userSex) {
         this.userSex = userSex;
     }


     public String getUserPhone() {
         return userPhone;
     }


     public void setUserPhone(String userPhone) {
         this.userPhone = userPhone;
     }


     public String getUserAddress() {
         return userAddress;
     }


     public void setUserAddress(String userAddress) {
         this.userAddress = userAddress;
     }

}

與資料庫連線的部份 使用 BasicDataSource 來取代傳統的 JDBC 連線:

package test.utils;



import org.apache.commons.dbcp.BasicDataSource;



import javax.sql.DataSource;



/**
  * Created by Hsu on 2015/4/16.
  */

public class DataSourceHolder {
     private BasicDataSource ds = new BasicDataSource();
     private DataSourceHolder(){
         ds.setDriverClassName("com.mysql.jdbc.Driver");
         ds.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=big5");
         ds.setUsername("test");
         ds.setPassword("test");
     }


     private static class SingletonHolder{
         private static DataSourceHolder instance = new DataSourceHolder();
     }


     public static DataSourceHolder getInstance(){
         return SingletonHolder.instance;
     }


     public DataSource getDataSources(){
         return  ds;
     }

}

要取得 Connection 實體 只要使用

DataSourceHolder.getInstance().getDataSources().getConnection();

即可獲得

接著建立 Dao 的部份

package test.Dao;



import org.apache.log4j.Logger;

import test.Models.USER_PROFILE;

import test.utils.DataSourceHolder;

import test.utils.StringUtil;



import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;



/**
  * Created by Hsu on 2015/4/16.
  */

public class UserProfileDao {
     Logger logger = Logger.getLogger(this.getClass());


     public List<USER_PROFILE> queryByCondition(USER_PROFILE user_profile){
         List<USER_PROFILE> list = new ArrayList<USER_PROFILE>();
         Connection conn = null;
         try{
             conn = DataSourceHolder.getInstance().getDataSources().getConnection();
             final String sql = "select * from user_profile where 1=1 " +
                     this.generateWhere(user_profile) + " order by user_id ";
             PreparedStatement ps = conn.prepareStatement(sql);
             this.preparePS(user_profile, ps);
             ResultSet rs = ps.executeQuery();
             while (rs.next()){
                 USER_PROFILE resultUserProfile = this.rs2Model(rs);
                 list.add(resultUserProfile);
             }
             rs.close();
             ps.close();
         }catch (SQLException sex){
             logger.error(sex.getMessage(),sex);
             sex.printStackTrace();
         }catch (Exception ex){
             logger.error(ex.getMessage(),ex);
             ex.printStackTrace();
         }finally {
             try{
                 conn.close();
             }catch (SQLException sex){
                 logger.error(sex.getMessage(),sex);
                 sex.printStackTrace();
             }
         }
         return list;
     }


     private String generateWhere(USER_PROFILE user_profile){
         StringBuffer sb = new StringBuffer();
         // 姓名查詢
         if(!"".equals(StringUtil.NulltoString(user_profile.getUserName()))){
             sb.append(" and user_name like ? ");
         }
         // 電話查詢
         if(!"".equals(StringUtil.NulltoString(user_profile.getUserPhone()))){
             sb.append(" and user_phone = ? ");
         }
         // 性別查詢
         if(!"".equals(StringUtil.NulltoString(user_profile.getUserSex()))){
             sb.append(" and user_sex = ? ");
         }
         return (sb.length()>0?sb.toString():"");
     }


     private void preparePS(USER_PROFILE user_profile, PreparedStatement ps) throws SQLException{
         int count = 1;
         if(!"".equals(StringUtil.NulltoString(user_profile.getUserName()))){
             ps.setString(count++, "%" + user_profile.getUserName() + "%");
         }
         if(!"".equals(StringUtil.NulltoString(user_profile.getUserPhone()))){
             ps.setString(count++, user_profile.getUserPhone());
         }
         if(!"".equals(StringUtil.NulltoString(user_profile.getUserSex()))){
             ps.setString(count++, user_profile.getUserSex());
         }
     }
     private USER_PROFILE rs2Model(ResultSet rs) throws Exception{
         USER_PROFILE user_profile = new USER_PROFILE();
         user_profile.setId(rs.getInt("id"));
         user_profile.setUserId(rs.getString("user_Id"));
         user_profile.setUserName(rs.getString("user_name"));
         user_profile.setUserPhone(rs.getString("user_phone"));
         user_profile.setUserSex(rs.getString("user_sex"));
         user_profile.setUserAddress(rs.getString("user_address"));
         return user_profile;
     }

}




裡面只單純提供了資料查找的功能,若有需要其他如 新增、移除、修改的部份,可另行加入對應的method。

Struts.xml 配置檔部分:

下面我們配置了 authorizationInterceptor 這個 Interceptor,好用來做驗證登入登出的訊息。

<?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.devMode" value="true" />
         <constant name="struts.locale" value="zh_TW" />
         <!-- 定義系統預設編碼集 -->
        
<constant name="struts.i18n.encoding" value="UTF-8" />
         <!-- 允許使用OGNL -->
        
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
         <!-- 允許 使用 DynamicMethodInvocation -->
        
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
         <!-- 使用struts2 ui -->
         <!-- <constant name="struts.ui.theme" value="simple" /> -->
        
<constant name="struts.ui.theme" value="xhtml" />


         <package name="crud" extends="struts-default">
                 <interceptors>
                         <interceptor name="authorizationInterceptor" class="test.Interceptors.AuthorizationInterceptor" />
                         <interceptor-stack name="myStack">
                                 <interceptor-ref name="authorizationInterceptor" />
                                 <interceptor-ref name="defaultStack" />
                         </interceptor-stack>
                 </interceptors>


                 <!-- <default-interceptor-ref name="myStack" /> -->


                
<global-results>
                         <result name="toList">/index.jsp</result>
                         <result name="error">/error.jsp</result>
                 </global-results>
                 <action name="*Methods" method="{1}"
                         class="test.Actions.MainAction">
                         <interceptor-ref name="myStack" />
                         <result name="success">/index.jsp</result>
                 </action>


                 <action name="Login" class="test.Actions.Login">
                         <result name="success">/index.jsp</result>
                 </action>


                 <action name="Logout" class="test.Actions.Logout">
                         <result name="success">/index.jsp</result>
                 </action>
         </package>

</struts>

而接著是最重要的 Action 部分:

package test.Actions;



import com.opensymphony.xwork2.ActionSupport;

import org.apache.struts2.interceptor.SessionAware;

import test.Dao.UserProfileDao;

import test.Models.USER_PROFILE;



import java.util.List;

import java.util.Map;



/**
  * Created by Hsu on 2015/4/16.
  */

public class MainAction extends ActionSupport implements SessionAware {
     private static final long serialVersionUID = -1651659160635719619L;
     private List<USER_PROFILE> list;
     private USER_PROFILE user_profile;
     private Map<String, Object> session;


     public String query() throws Exception{
         System.out.println("query Method");
         UserProfileDao dao = new UserProfileDao();
         list = dao.queryByCondition(user_profile);
         //session.clear();
         return "toList";
     }


     public List<USER_PROFILE> getList() {
         return list;
     }


     public void setList(List<USER_PROFILE> list) {
         this.list = list;
     }


     public USER_PROFILE getUser_profile() {
         return user_profile;
     }


     public void setUser_profile(USER_PROFILE user_profile) {
         this.user_profile = user_profile;
     }


     @Override
     public void setSession(Map<String, Object> session) {
         System.out.println("Get Session OK...");
         this.session = session;
     }


     @Override
     public String execute() throws Exception {
         System.out.println("execute Method");
         return SUCCESS;
     }

}

裡面最主要的 Method 就是 query(),也就是我們在 Struts.xml 中所配置的 Action其對應的方法。

private List<USER_PROFILE> list;
private USER_PROFILE user_profile;

上面所列的兩個屬性,則是用於對照到 index.jsp 所用到的資料,如:

<s:if test="null!=list&&!list.isEmpty()">
     <hr>
     <s:iterator value="list">

<s:textfield name="user_profile.userName" label="使用者姓名"/>

上面的原始碼中,我 implements SessionAware 這個類別,主要就是要用來取得 Session 的資料。

因為依照題意,我們需要取得Session 的相關資訊,且要在 interceptor 中做判斷,底下就是interceptor 的實作。

package test.Interceptors;



import com.opensymphony.xwork2.Action;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.AbstractInterceptor;



import java.util.Map;



/**
  * Created by Hsu on 2015/4/21.
  * Ref: http://www.mkyong.com/struts2/struts-2-creating-own-interceptor/
  */

public class AuthorizationInterceptor extends AbstractInterceptor

{
     @Override
     public String intercept(ActionInvocation invocation) throws Exception {
         System.out.println("intercept enter");
         Map session = invocation.getInvocationContext().getSession();
         String userParam = (String)session.get("USER");
         if(null != userParam){
             System.out.println("userParam:" + userParam);
             if(!"LOGIN".equals(userParam)){
                 System.out.println("return Action.ERROR");
                 return Action.ERROR;
             }
             System.out.println("invocation.invoke()");
             return invocation.invoke();
         }else{
             System.out.println("userParam:" + userParam);
             System.out.println("return Action.ERROR");
             return Action.ERROR;
         }
     }

}

上面其中的

Map session = invocation.getInvocationContext().getSession();

就是用來取得 Session 的資料用,下面接著就是判斷,若含有 LOGIN 的字串Action 就繼續進行,若無則導致錯誤頁面。

而因為我們要虛擬登入/登出動作,故多增加了 Login及Logout 兩個 action

package test.Actions;



import com.opensymphony.xwork2.ActionSupport;

import org.apache.struts2.interceptor.SessionAware;



import java.util.Map;



/**
  * Created by Hsu on 2015/4/21.
  */

public class Login extends ActionSupport implements SessionAware {
     Map<String, Object> session;
     @Override
     public String execute() throws Exception {
         // 虛擬登入
         System.out.println("User Login!!!!");
         session.put("USER","LOGIN");
         return SUCCESS;
     }


     @Override
     public void setSession(Map<String, Object> session) {
         this.session = session;
     }

}
package test.Actions;



import com.opensymphony.xwork2.ActionSupport;

import org.apache.struts2.interceptor.SessionAware;



import java.util.Map;



/**
  * Created by Hsu on 2015/4/21.
  */

public class Logout extends ActionSupport implements SessionAware {
     Map<String, Object> session;
     @Override
     public String execute() throws Exception {
         // 虛擬登出
         System.out.println("Session Clear!!!!");
         session.clear();
         return SUCCESS;
     }


     @Override
     public void setSession(Map<String, Object> session) {
         this.session = session;
     }

}

上面兩個action,主要是將資料放進 session跟清除 session 中的資料用,當然也可以整合在MainAction 中,用method的方式去實作。

【程式執行畫面】

未點選登入時直接點選查詢

clip_image004

沒有留言 :

張貼留言