bos项目总结

这是一个物流管理系统,项目是由maven构建的,用到了ssh框架,前台页面是由jquery easyUi来完成的,它使页面实现了静态化,因为大部分请求都是后台返回前台json字符串,前台根据这些json字符串进行页面处理,


项目底层代码构建

因为dao层代码有很多都是重复的,所以我们对他们进行了提取,用到了反射和泛型

接口IBasDao.java

package com.yinhe.bos.dao;

import java.io.Serializable;
import java.util.List;

import com.yinhe.bos.utils.PageUtils;

public interface IBaseDao<T> {

	//增
	public void save(T javabean);
	
	public void saveOrUpdate(T javabean);
	//删
	public void del(T entity);
	//改
	public void update(T entity);
	//根据id查询
	public T get(Serializable id);
	//查询所有数据
	public List<T> find();
	
	/**
	 * 
	 * @param queryname
	 * @param objects
	 */
	public void executeUpdate(String queryname,Object...objects);
	
	//分页查询
	public void findByPage(PageUtils pageUtils);
}

实现类BaseDaoImpl.java

package com.yinhe.bos.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.yinhe.bos.dao.IBaseDao;
import com.yinhe.bos.utils.PageUtils;

public class BaseDaoImpl<T> extends HibernateDaoSupport implements IBaseDao<T> {

	private Class<T> clazz;
	//在tomcat启动加载spring容器时调用
	//早构造方法中通过反射获取clazz对象
	
	public IBaseDaoImpl() {
		// TODO Auto-generated constructor stub
		//获取父类对应的class对象
		//this代表继承的子类对象
		ParameterizedType superClazz=(ParameterizedType)this.getClass().getGenericSuperclass();
		//获取父类所有的泛型类数组
		Type[] type=superClazz.getActualTypeArguments();
		clazz=(Class<T>) type[0];
	}
	@Resource
	public void initHibernateT(SessionFactory sessionFactory){
		super.setSessionFactory(sessionFactory);
		//this.setSessionFactory(sessionFactory);
	}
	
	@Override
	public void save(T javabean) {
		// TODO Auto-generated method stub
		this.getHibernateTemplate().save(javabean);
	}
	
	@Override
	public void saveOrUpdate(T javabean) {
		// TODO Auto-generated method stub
		this.getHibernateTemplate().saveOrUpdate(javabean);
	}

	public void del(T entity){
		
	}
	
	public void update(T entity){
		this.getHibernateTemplate().update(entity);
	}
	
	public T get(Serializable id){
		
		return this.getHibernateTemplate().get(clazz, id);
		
	}
	
	public List<T> find(){
		return (List<T>) this.getHibernateTemplate().find("from "+clazz.getSimpleName());
	}
	
	public void executeUpdate(String queryname,Object...objects){
		Session session=this.getSessionFactory().getCurrentSession();
		Query query=session.getNamedQuery(queryname);
		for (int i = 0; i < objects.length; i++) {
			query.setParameter(i, objects[i]);
			
		}
		query.executeUpdate();
		
	}
	
	public void findByPage(PageUtils pageUtils){
		DetachedCriteria criteria=pageUtils.getCriteria();
		List list=this.getHibernateTemplate().findByCriteria(criteria.setProjection(Projections.count("id")));
		pageUtils.setTotal(((Long)list.get(0)).intValue());
		criteria.setProjection(null);
		criteria.setResultTransformer(Criteria.ROOT_ENTITY);
		pageUtils.setRows(this.getHibernateTemplate().findByCriteria(criteria,pageUtils.getStart(),pageUtils.getPageSize()));
	}
	
}
其他dao层接口实现BaseDao接口,dao层实现类继承BaseDaoImpl类就可以,省下了很多代码。

action层的抽取

BaseAction.java

package com.yinhe.bos.web.controller;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.apache.struts2.ServletActionContext;
import org.hibernate.criterion.DetachedCriteria;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.yinhe.bos.domain.Staff;
import com.yinhe.bos.utils.PageUtils;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

public class BaseAction<T> extends ActionSupport implements ModelDriven<T>{
	//提取分页查询
	protected int page;
	protected int rows;
	protected PageUtils pageUtils=new PageUtils();
	protected T model;
	@Override
	public T getModel() {
		// TODO Auto-generated method stub
		return model;
	}
	public BaseAction() {
		// TODO Auto-generated constructor stub
		ParameterizedType superClazz=(ParameterizedType)this.getClass().getGenericSuperclass();
		//获得BaseAction上声明的泛型数组
		Type[] types=superClazz.getActualTypeArguments();
		Class<T> clazz=(Class<T>) types[0];
		pageUtils.setCriteria(DetachedCriteria.forClass(clazz));
		try {
			model=clazz.newInstance();
			
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	protected void objectJson(Object o,String[]strs) throws IOException{
		JsonConfig jsonConfig=new JsonConfig();
		jsonConfig.setExcludes(strs);
		ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
		//为什么关闭懒加载
		/*
		 * jsonConfig排除只是给当前对象o设置的,转换json的时候,subarea里的region要重新从数据库里查,而查出来的region里又有
		 * subarea,这个是没有设置排除的,所以会无限循环
		 */
		String a=JSONObject.fromObject(o, jsonConfig).toString();
		
/*		JSONObject jo=JSONObject.fromObject(pageUtils);
		String a=jo.toString();*/
		ServletActionContext.getResponse().getWriter().print(a);
	}
	protected void arrayJson(List list,String[]strs) throws IOException{
		JsonConfig jsonConfig=new JsonConfig();
		jsonConfig.setExcludes(strs);
		ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
		String a=JSONArray.fromObject(list, jsonConfig).toString();
		
/*		JSONObject jo=JSONObject.fromObject(pageUtils);
		String a=jo.toString();*/
		ServletActionContext.getResponse().getWriter().print(a);
	}
	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		pageUtils.setPageSize(rows);
		pageUtils.setStart((page-1)*rows);
	}
}
其他action继承BaseAction类即可,这样就不用再每个action类里创建一个model对象了



一,登录

用ajax发送请求,根据后台返回数据来判断用户名密码是否正确,整个项目用到了登录验证拦截器,struts2实现拦截器的方式有三种,1,实现Interceptor接口;2,继承AbstractInterceptor类;3,继承MethodFilterInterceptor类,这里我们用第三种,它有一个特点就是可以排除对action中指定方法的拦截或只拦截指定额方法,

<!-- 配置拦截器 -->
<interceptors>
<!-- 配置自定义拦截器 -->
<interceptor name="myInterceptor" class="com.caokaiyuan.interceptor.MyInterceptor"></interceptor>
<!-- 配置拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack"/><!-- 加载默认拦截器 -->
<!-- 加载自定义拦截器 -->
<interceptor-ref name="myInterceptor">
<!-- 配置要拦截的方法;user,client为方法名 -->
<param name="includeMethods">user,client</param>
<!-- 配置不需要拦截的方法;login为方法名 -->
<param name="excludeMethods">login</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
登录成功后来到主页,如下图


主页分为上中左下四个区域,是由easyUI里的layout页面布局实现的,左边部分是个菜单树,由jquery ztree插件来完成的,


二,取派员设置

实现了增删改和分页查询,增加用到了easyUi中的validatebox校验,只有当数据全部输入正确后才可以提交,

分页查询数据显示用到了easyUi中的datagrid,它类似于一个表格,但功能很强大,通过发送ajax请求获取json数据创建datagrid

		// 取派员信息表格
		$('#grid').datagrid( {
			iconCls : 'icon-forward',
			fit : true,
			border : false,
			rownumbers : true,
			striped : true,
			pageList: [5,20,30],
			pagination : true,
			toolbar : toolbar,
			url : "${pageContext.request.contextPath }/staffAction_select.action",
			idField : 'id',
			columns : columns,
			onDblClickRow : doDblClickRow
		});
对分页查询所需数据进行封装

PageUtil.java

package com.yinhe.bos.utils;

import java.util.List;

import org.hibernate.criterion.DetachedCriteria;

import com.yinhe.bos.domain.Staff;

public class PageUtils {
	private int total;
	private List rows;
	private int start;
	private int pageSize;
	private DetachedCriteria criteria;
	public int getTotal() {
		return total;
	}
	public void setTotal(int total) {
		this.total = total;
	}
	public List getRows() {
		return rows;
	}
	public void setRows(List rows) {
		this.rows = rows;
	}
	public int getStart() {
		return start;
	}
	public void setStart(int start) {
		this.start = start;
	}
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
	public DetachedCriteria getCriteria() {
		return criteria;
	}
	public void setCriteria(DetachedCriteria criteria) {
		this.criteria = criteria;
	}
	
	
}
之后根据前台所发请求和参数,进行查询,返回相应的json数据即可

修改,首先要进行数据回显,一般回显,我们要去数据库查询,然后根据查询到的数据进行回显,然而我们用了datagrid,它可以帮我们进行数据的回显


回显后,修改数据交给后台处理即可。

删除其实是假删除,在数据库生成一个字段,值为1表示当前取派员存在,为0则表示不存在,即删除。


三,区域设置,实现功能有将excel表导入数据库分页查询,


导入用到了apache POI技术和pinyin4j,POI上篇博客有介绍,这里不再多说,excel表里只有省市区邮箱,而没有简码和城市编码,(简码就是市和区的拼音首字母,城市简码是市的拼音),所以这里就用到了pinyin4j,可以进行中文字符和拼音之间的转换。拼音输出格式可以定制。分页查询和上面取派员分页查询思路一样。


四,管理分区


实现了查询,增加和导出,区域和分区是一对多的关系,

条件查询


第一步:提供一个工具方法,可以将指定的form表单中所有的输入项转为json数据,用于参数提交

		//定义一个工具方法,用于将指定的form表单中所有的输入项转为json数据{key:value,key:value}
		$.fn.serializeJson=function(){  
            var serializeObj={};  
            var array=this.serializeArray();
            $(array).each(function(){  
                if(serializeObj[this.name]){  
                    if($.isArray(serializeObj[this.name])){  
                        serializeObj[this.name].push(this.value);  
                    }else{  
                        serializeObj[this.name]=[serializeObj[this.name],this.value];  
                    }  
                }else{  
                    serializeObj[this.name]=this.value;   
                }  
            });  
            return serializeObj;  
第二步:为查询窗口中查询按钮绑定事件

$("#btn").click(function(){
			//将指定的form表单中所有的输入项转为json数据{key:value,key:value}
			var p = $("#searchForm").serializeJson();
			console.info(p);
			//调用数据表格的load方法,重新发送一次ajax请求,并且提交参数
			$("#grid").datagrid("load",p);
			//关闭查询窗口
			$("#searchWindow").window("close");
		});

根据前台传递的参数,后台action中添加对应的模糊查询字段即可,因为这是qbc多表查询,所以要给表取别名,查询完后发现返回的数据格式有问题,这是因为

实体间有定义关联关系的(一对多,多对一等)
对已定义关联关系的,我们可以使用createAlias()来创建属性的别名,然后引用别名进行条件查询,如:
Criteria criteria = session.createCriteria(Parent.class);  
criteria.createAlias("children", "c").add(Expression.eq( "c.name" ,  childName));
这样进行查询时就可得到关联查询后的Parent对象结果集。
要注意的是,如果在createAlias()之后,又使用了setProjection(如查询总记录数),这样得到的查询结果集中,每个对象并不是Parent类型,而是一个对象数组(Object[]),里边有一个Parent对象和一个Child对象,需要根据object的类名去判断是哪个对象。
如果还要恢复默认的结果集状态,需调用
criteria.setResultTransformer(Criteria.ROOT_ENTITY);
这样返回的数据就没有问题了,
数据导出也是用到了POI技术,上几遍博客有具体介绍


最后一个功能是添加分区,
用到了easyUi里的下拉框,
<input class="easyui-combobox" name="region.id" data-options="valueField:'id',textField:'name',url:'${pageContext.request.contextPath }/regionAction_find',mode:'remote'" />  

界面加载完,去请求input里的url,通过返回json字符串来进行下拉框内数据的显示,当用户在下拉框进行输入后,也会向后台请求这个url,并且发送一个参数q,就是用户输入的内容,我们就用这个来进行模糊查询,重新返回json字符串,实现搜索功能
用户将数据填写完整后,点击保存发送请求,后台进行数据库插入操作。

注意:如果连个对象有关联,那么对象转换成json字符串就会出现死循环问题,解决方法:
1、页面不需要展示关联数据时
解决:将关联对象属性排除掉

2、页面需要展示关联数据时
解决:将关联对象改为立即加载,并且将关联对象中的属性排除


功能没有实现完,但收获依然很大,以上就是主要功能简述,记录下来以便以后回顾。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值