[项目实战] ibatis +spring+struts2+jquery.autocomplete实现产品自动补全功能(二) 附带源码

这两天忙公司的项目,没有把项目的demo写出来。趁现在空闲,偷偷的写一下。奋斗
先上demo结构目录图:

大家看到了吧,项目层次分得很清楚。
config  是 spring和itatis的配置文件。接下来就是经典的mvc分层架构啦,bean  ----  dao ---- service -----  action ---  view。理论的东西,我就不多说了。下面我按照这个demo开发流程一步一步写出来:
一。在eclipse新建项目,导入jar包,有木有??!!!

 

二。集成spring和struts,web.xml文件配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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>ctcoms</display-name>
	<description>A Java Forum System Based on Struts2</description>
	<!--  加载spring 配置文件 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:config/spring*.xml</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<!-- 定义Struts 2的FilterDispatcher的Filter -->
	<filter>
		<!-- 定义核心Filter的名字 -->
		<filter-name>struts2</filter-name>
		<!-- 定义核心Filter的实现类 -->
		<filter-class>
			org.apache.struts2.dispatcher.FilterDispatcher
		</filter-class>
		<!-- 设置编码 -->
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
	</filter>

	<!-- FilterDispatcher用来初始化Struts 2并且处理所有的Web请求 -->
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- jsp等头文件的过滤器,解决乱码用 -->
	<filter>
		<filter-name>AddHeaderFilter</filter-name>
		<filter-class>
			org.mission.ctcoms.web.filter.AddHeaderFilter
		</filter-class>
		<init-param>
			<param-name>headers</param-name>
			<param-value>Content-Encoding=gzip</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>AddHeaderFilter</filter-name>
		<url-pattern>*.gzjs</url-pattern>
	</filter-mapping>
	<welcome-file-list>
		<welcome-file>/login.jsp</welcome-file>
		<welcome-file>/index.jsp</welcome-file>
	</welcome-file-list>


	<error-page>
		<exception-type>java.lang.Exception</exception-type>
		<location>/error.jsp</location>
	</error-page>
</web-app>


三。项目里,spring是用来配置数据库,事物管理,配置ibatis, 管理struts的action,管理dao层的bean,管理service的bean。相关的配置文件如下图:

 

四。在classpath路径下,新建struts.xml 和log4j.properties 文件,分别是 struts的映射文件 和 日志信息的配置。

 

五。把配置文件建好以后,就开始写代码了。这个demo业务很简单,只有一个bean,一张表就足够了。表的话 大家就自己建把,一个主键,一个产品名就OK啦。

bean的代码就不贴出来了,就是getter 和setting方法。

 

六。建立ibatis的sql配置文件,StoreProduct.xml如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap      
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"      
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="StoreProduct">
	<select id="findStoreProdctListNameForJson"  parameterClass="java.lang.String" resultClass="java.lang.String" >
		select S.name from zy_store_product S where lower(S.name)  LIKE lower('%$productName$%')
	</select>
</sqlMap>

namespace 就是 sql的命名空间;findStoreProdctListNameForJson   为 调用sql 的唯一标识id; parameterClass 为参数类型,这里是传了一个产品名的字符串;resultClass为返回值类型。

select S.name from zy_store_product S where lower(S.name) LIKE lower('%$productName$%')  就是一句标准的sql语句了,$productName$ 代表参数。在这里可以执行任何复杂的sql语句,这就是

ibatis的灵活之处。ibatis的用法这里就不详细说了,以后有机会贴上一篇ibatis的增删查改的demo。

 

七。封装一个操作ibatis的类,用于简化ibatis的crud(增删查改)操作,每个dao都要继承这个类。BaseIbaitsDAO 如下:

package org.mission.ctcoms.ibatis;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.mission.ctcoms.exception.ApplicationException;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

/**
 * 
 * @author 黄宇强
 * @date  2011-8-5 上午09:27:06
 * @description This base class is prepared for subclass to do CRUD easily.
 */
public class BaseIbaitsDAO extends SqlMapClientDaoSupport {
	private Logger log4j = Logger.getLogger(BaseIbaitsDAO.class);

	/**
	 * 根据条件查询对象集合
	 * 
	 * @param sqlid
	 *            对应IBATIS xml SQL_ID
	 * @param paramObj
	 *            参数对象
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> loadList(String sqlid, Object paramObj) {
		return (List<T>) getSqlMapClientTemplate()
				.queryForList(sqlid, paramObj);
	}

	/**
	 * 根据条件查询对象所有数据
	 * 
	 * @param <T>
	 * @param sqlid
	 *            对应IBATIS xml SQL_ID
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> loadList(String sqlid) {
		return (List<T>) getSqlMapClientTemplate().queryForList(sqlid);
	}

	/**
	 * 根据ID查询ENTITY 对象
	 * 
	 * @param <T>
	 * @param sqlid对应IBATIS
	 *            xml SQL_ID
	 * @return <T> 实体对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T loadObject(String sqlid) {
		return (T) getSqlMapClientTemplate().queryForObject(sqlid);
	}

	/**
	 * 根据ID查询ENTITY 对象
	 * 
	 * @param <T>
	 * @param sqlid对应IBATIS
	 *            xml SQL_ID
	 * @param id
	 *            实体ID
	 * @return <T> 实体对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T loadObject(String sqlid, String id) {
		return (T) getSqlMapClientTemplate().queryForObject(sqlid, id);
	}

	/**
	 * 根据ID查询ENTITY 对象
	 * 
	 * @param <T>
	 * @param sqlid对应IBATIS
	 *            xml SQL_ID
	 * @param id
	 *            实体ID
	 * @return <T> 实体对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T loadObject(String sqlId, Long id) {
		return (T) getSqlMapClientTemplate().queryForObject(sqlId, id);
	}

	/**
	 * 根据条件查询对象
	 * 
	 * @param <T>
	 * @param sqlid对应IBATIS
	 *            xml SQL_ID
	 * @param paramObj
	 *            参数
	 * @return <T> 实体对象
	 */
	@SuppressWarnings("unchecked")
	public <T> T loadObject(String sqlId, Object paramObj) {
		return (T) getSqlMapClientTemplate().queryForObject(sqlId, paramObj);
	}

	/**
	 * 保存对象
	 * 
	 * @param sqlid
	 *            对应IBATIS xml SQL_ID
	 * @param entity
	 *            保存的对象
	 */
	public void save(String sqlid, Object entity) {
		getSqlMapClientTemplate().insert(sqlid, entity);
	}

	/**
	 * 保存对象
	 * 
	 * @param sqlid
	 *            对应IBATIS xml SQL_ID
	 * @param entity
	 *            保存的对象
	 */
	public void save(String sqlid, Map<String, Object> entity) {
		getSqlMapClientTemplate().insert(sqlid, entity);
	}

	/**
	 * 更新对象
	 * 
	 * @param sqlid
	 *            对应IBATIS xml SQL_ID
	 * @param entity
	 *            修改对象
	 */
	public void update(String sqlId, Map<String, Object> entity) {
		getSqlMapClientTemplate().update(sqlId, entity);
	}

	/**
	 * 更新对象
	 * 
	 * @param sqlid
	 *            对应IBATIS xml SQL_ID
	 * @param entity
	 *            修改对象
	 */
	public void update(String sqlId, Object entity) {
		getSqlMapClientTemplate().update(sqlId, entity);
	}

	/**
	 * 删除指定的对象
	 * 
	 * @param sqlId
	 * @param object
	 *            需要删除的对象
	 */
	public void delete(String sqlId, Object object) {
		getSqlMapClientTemplate().delete(sqlId, object);
	}

	/**
	 * 查询数据总条数
	 * 
	 * @param sqlid
	 * @param object
	 * @return
	 */
	public Long loadRecordCountObject(String sqlid, Object object) {
		log4j.info("sqlid====" + sqlid);
		return (Long) getSqlMapClientTemplate().queryForObject(sqlid, object);
	}

	/**
	 * 查询数据总条数
	 * 
	 * @param sqlid
	 * @param object
	 * @return 返回Int
	 */
	public Integer loadRecordCount(String sqlid, Object object) {
		log4j.info("sqlid====" + sqlid);
		return (Integer) getSqlMapClientTemplate()
				.queryForObject(sqlid, object);
	}

	/**
	 * @Title: findTNextId
	 * @Description: 返回表中ID最大值加一
	 * @param:
	 * @param tabName
	 *            表名
	 * @return:
	 * @returnType: Long
	 * @throws
	 */
	public Long findTNextId(String tabName) {
		Long id = 0l;
		String seqName = tabName.substring(3) + "_S";
		id = (Long) getSqlMapClientTemplate().queryForObject(
				"Common.findTNextId", seqName);
		if (id == null || id.equals(0l))
			throw new ApplicationException("ID查询错误");
		return id;
	}

	public Date findOracleSysdate() {

		return (Date) getSqlMapClientTemplate().queryForObject(
				"Common.findOracleSysdate", null);
	}

}


 

八。用到spring ,是基于接口的编程了。分别实现 service、dao层的接口以及其实现类。需要注意的是,每个service、dao都要写进spring的相关配置文件去,实现spring对bean的管理。

 

 

九。crum的代码写好了,就到action层了。

package org.mission.ctcoms.web.action.storage;

import java.util.List;

import org.apache.log4j.Logger;
import org.mission.ctcoms.business.storage.IStoreProductService;
import org.mission.ctcoms.web.code.BaseAction;

public class StorageProductAction extends BaseAction {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;


	private Logger log4j = Logger.getLogger(StorageProductAction.class);

	private IStoreProductService storeProductService;

	private List<String> content;  //传到前台显示用

	private String productName; // 产品名


	public String findStoreProdctListNameForJson() {
		try {
			String newProductName = new String(productName.getBytes("ISO-8859-1"),"utf-8");  // !!!解决参数乱码
			List<String> list = storeProductService.findStoreProdctListNameForJson(newProductName);
			this.setContent(list);
		} catch (Exception e) {
			log4j.error("findStoreProdctListNameForJson error", e);
		}

		return SUCCESS;

	}



	public Logger getLog4j() {
		return log4j;
	}

	public void setLog4j(Logger log4j) {
		this.log4j = log4j;
	}


	public IStoreProductService getStoreProductService() {
		return storeProductService;
	}

	public void setStoreProductService(IStoreProductService storeProductService) {
		this.storeProductService = storeProductService;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public List<String> getContent() {
		return content;
	}

	public void setContent(List<String> content) {
		this.content = content;
	}


}

 

然后,该action查询到的数据库数据是以json方传递到前台的,所以该action注册到struts的配置文件如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

	<package name="json-storage"
		extends="json-default">
		 <action name="findStoreProdctListNameForJson" method="findStoreProdctListNameForJson"
			class="storageProductAction">
			<result type="json">
				<param name="root">content</param>
			</result>
		</action>
	</package>	
	<constant name="struts.action.extension" value="do" />
</struts>


其中 content是json的标识,与action的content和稍后提及的jquery调用 相对应。extends="json-default" 是继承 struts-json插件的方法。


注: 该action 继承了封装好了的BaseAction,该类如下:

package org.mission.ctcoms.web.code;

import java.io.IOException;
import java.io.PrintWriter;

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

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 
 * @author 黄宇强
 * @date  2011-8-5 上午09:25:04
 * @description 抽象类
 */ 
public class BaseAction extends ActionSupport {
	/**
	 * 
	 */
	private static final long serialVersionUID = -4025716041310497629L;

	private Logger log4j = Logger.getLogger(BaseAction.class);

	public String jsonString;

	public void outJsonString(String str) {
		getResponse().setContentType("text/javascript;charset=UTF-8");
		outString(str);
	}

	public void outString(String str) {
		try {
			PrintWriter out = getResponse().getWriter();
			out.write(str);
		} catch (IOException e) {
			e.printStackTrace();
			log4j.error("out print failed:" + e);
		}
	}

	public void outXMLString(String xmlStr) {
		getResponse().setContentType("application/xml;charset=UTF-8");
		outString(xmlStr);
	}

	/**
	 * 获得request
	 * 
	 * @return
	 */
	public HttpServletRequest getRequest() {
		return ServletActionContext.getRequest();
	}

	/**
	 * 获得response
	 * 
	 * @return
	 */
	public HttpServletResponse getResponse() {
		return ServletActionContext.getResponse();
	}

	/**
	 * 获得session
	 * 
	 * @return
	 */
	public HttpSession getSession() {
		return getRequest().getSession();
	}

	/**
	 * 获得servlet上下文
	 * 
	 * 
	 * 
	 * @return
	 */
	public ServletContext getServletContext() {
		return ServletActionContext.getServletContext();
	}

	public String getRealyPath(String path) {
		return getServletContext().getRealPath(path);
	}

}


十。最后一步了,就是到前台页面。如何调用jquery.autocomplete,这个很简单,下载官方的demo下来,很容易就看明白了。贴出jsp的实现页面:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    
    <title>产品自动补全</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<script type="text/javascript" src="jquery/jquery.js"></script>
	<script type="text/javascript" src="jquery/jquery.autocomplete.js"></script>
	<link rel="Stylesheet" type="text/css" href="jquery/jquery.autocomplete.css" />
	<script type="text/javascript">
		var v_product_Store ;
		$().ready(function() {
			$("#productName").autocomplete("findStoreProdctListNameForJson.do", {  //当用户输入关键字的时候 ,通过 url的方式调用action的findStoreProdctListNameForJson方法
				minChars: 1,  //最小显示条数
				max: 12,  //最大显示条数
				autoFill: false,
				dataType : "json",  //指定数据类型的渲染方式
				extraParams: 
		        {   
		             productName: function() 
		              { 
		               return $("#productName").val();    //url的参数传递
		              }   
		           },

				 //进行对返回数据的格式处理
        		 parse: function(data) 
         			{
		             var rows = [];
		               for(var i=0; i<data.length; i++)
		           		 {	
			                 rows[rows.length] = {
			                   data:data[i],
			                   value:data[i],
			                  //result里面显示的是要返回到列表里面的值  
			                   result:data[i]
			                 };
		               }           
	               	return rows;
	           	},
				formatItem: function(item) {
					//没有特殊的要求,直接返回了
                  		return item;
				}
			});
		
		});
	</script>		
		
  </head>
  
  <body>
	  <div>
	  	 产品名: <input type="text" id="productName" />
	  </div>
  </body>
</html>


OK!搞定!再看一下效果图:

有什么问题,欢迎大家多多交流。上学的时候就不喜欢写作文,写完这篇博客就累趴了。但是能记录下自己编程道路下的点点滴滴 与大家分享,也是件乐事。写得不好的话,还请“砖家”们手下留情。。(ˇˍˇ)

 

 源码地址 :http://download.csdn.net/source/3497182

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值