2015年4月17日 星期五

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

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

【開發環境】

Tomcat 7

MySQL

【開發工具】

Intellij IDEA 14

【使用FrameWork】

Struts2

jQuery

【主要畫面】

clip_image002

簡單的說就是與資料庫結合來查找資料,使用 BasicDataSource 搭配 MySQL 使用。

【使用到的 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`;

底下分為兩種做法,一種是標準的 struts.xml 配置,一種是使用 Annotation。

先使用 Intellij IDEA 建立一個 maven 的 webapp 專案。

==========接下來是共通的部份==========

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_easy_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_easy_1</h2>

<s:form action="userQuery" method="POST">
             <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>



</body>

</html>

上面的部分簡單的使用 jQuery 建立 checkbox 檢核機制,當選男的,就會消除女的,反之亦然,另外在整張form 的部份,使用的 struts2 的 s tag,並建立對應的 model 與頁面使用

Model 部分;

USER_PROFILE.java 對應到資料庫的 Table

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。

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

先說使用 struts.xml 來配置的方式,及對應的 struts.xml 檔。

<?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" />
         <!--
使用struts2 ui -->
         <!-- <constant name="struts.ui.theme" value="simple" /> -->
        
<constant name="struts.ui.theme" value="xhtml" />


         <package name="query" extends="struts-default">
                 <global-results>
                         <result name="toList">/index.jsp</result>
                 </global-results>
                 <action name="userQuery" class="test.Actions.MainAction" method="query" />
         </package>

</struts>

上面就是 整個 Action 的運作流程,使用 method 對應所要執行的方法,並設定 global-results,當傳回的 String = toList ,則一律導到 /index.jsp 的頁面。

而對應此 struts.xml 的 MainAction.java 內容如下:

package test.Actions;



import com.opensymphony.xwork2.ActionSupport;

import test.Dao.UserProfileDao;

import test.Models.USER_PROFILE;



import java.util.List;



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

public class MainAction extends ActionSupport {
     private static final long serialVersionUID = -1651659160635719619L;
     private List<USER_PROFILE> list;
     private USER_PROFILE user_profile;


     public String query() throws Exception{
         UserProfileDao dao = new UserProfileDao();
         list = dao.queryByCondition(user_profile);
         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;
     }

}

裡面最主要的 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="使用者姓名"/>

接著來說明使用 Annotation 的部份,上面所述的 Struts.xml 已經可以不用了,只需要對 MainAction

作些許修改,內容如下:

package test.action;



import com.opensymphony.xwork2.ActionSupport;

import org.apache.struts2.convention.annotation.*;

import test.Dao.UserProfileDao;

import test.Models.USER_PROFILE;



import java.util.List;



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

@ParentPackage(value = "struts-default")

@Namespace("/")

@Results({
         @Result(name = "toList",location = "/index.jsp")

})

public class MainAction extends ActionSupport {
     private static final long serialVersionUID = -1651659160635719619L;
     private List<USER_PROFILE> list;
     private USER_PROFILE user_profile;


     @Action("/userQuery")
     public String query() throws Exception{
         UserProfileDao dao = new UserProfileDao();
         list = dao.queryByCondition(user_profile);
         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;
     }

}

簡單說明一下:

@ParentPackage(value = "struts-default")

@Namespace("/")

@Results({
         @Result(name = "toList",location = "/index.jsp")

})

上面這段的配置,等於 Struts.xml 中的

<package name="query" extends="struts-default">
         <global-results>
                 <result name="toList">/index.jsp</result>
         </global-results>

</package>

@Action("/userQuery")

等於

<action name="userQuery" class="test.Actions.MainAction" method="query" />

另外有一點要特別注意的是,若您是使用 Annotation + Method 的配置方式,所有Aciton 需要依循一個原則,參照:http://blog.csdn.net/z69183787/article/details/8135793 最後所提到的:

First the Convention plugin finds packages named struts, struts2, action or actions. Any packages that match those names are considered the root packages for the Convention plugin. Next, the plugin looks at all of the classes in those packages as well as sub-packages and determines if the classes implementcom.opensymphony.xwork2.Action or if their name ends with Action (i.e. FooAction).

簡單說,就是要放在 package 名稱為 struts, struts2, action, actions包或者其子 package 中,否則會發生像 There is no Action mapped for namespace [/]…… 這樣的錯誤。

另外在 prom.xml 的部份,若使用 Annotation 的配置方式,需多載入三個 dependency,分別為

<properties>

……

<struts2-convention-plugin.version>2.3.16.3</struts2-convention-plugin.version>

<asm.version>3.3.1</asm.version>

<asm-commons.version>3.3.1</asm-commons.version>

……

</properties>

<!-- struts2 annotation 用 -->

<dependency>

<groupId>org.apache.struts</groupId>

<artifactId>struts2-convention-plugin</artifactId>

<version>${struts2-convention-plugin.version}</version>

</dependency>

<dependency>

<groupId>asm</groupId>

<artifactId>asm</artifactId>

<version>${asm.version}</version>

</dependency>

<dependency>

<groupId>asm</groupId>

<artifactId>asm-commons</artifactId>

<version>${asm-commons.version}</version>

</dependency>

 


原始程式下載: http://goo.gl/27PO0e

1 則留言 :