纳税服务系统六(信息发布管理模块)【Ueditor、异步信息交互、抽取BaseService、条件查询、分页】...

需求分析

我们现在来到了纳税服务系统的信息发布管理模块,首先我们跟着原型图来进行需求分析把:

一些普通的CRUD,值得一做的就是状态之间的切换了。停用和发布切换。


640?wx_fmt=png

值得注意的是:在信息内容中,它可以带格式地复制内容,然后上传到我们的服务器中。

640?wx_fmt=png

流程图:


640?wx_fmt=png

编写JavaBean与配置文件

javaBean

package zhongfucheng.info.entity;import java.sql.Timestamp;import java.util.HashMap;import java.util.Map;public class Info implements java.io.Serializable {    private String infoId;    private String type;    private String source;    private String title;    private String content;    private String memo;    private String creator;    private Timestamp createTime;    private String state;    public static String INFO_STATE_PUBLIC = "1";//发布    public static String INFO_STATE_STOP = "0";//停用    public static String INFO_TYPE_TZGG = "tzgg";    public static String INFO_TYPE_ZCSD = "zcsd";    public static String INFO_TYPE_NSZD = "nszd";    public static Map<String, String> INFO_TYPE_MAP = new HashMap<String, String>();    static {        INFO_TYPE_MAP.put(INFO_TYPE_TZGG, "通知公告");        INFO_TYPE_MAP.put(INFO_TYPE_ZCSD, "政策速递");        INFO_TYPE_MAP.put(INFO_TYPE_NSZD, "纳税指导");    }    public Info() {    }    public Info(String title) {        this.title = title;    }    public Info(String type, String source, String title, String content, String memo, String creator, Timestamp createTime, String state) {        this.type = type;        this.source = source;        this.title = title;        this.content = content;        this.memo = memo;        this.creator = creator;        this.createTime = createTime;        this.state = state;    }    public String getInfoId() {        return this.infoId;    }    public void setInfoId(String infoId) {        this.infoId = infoId;    }    public String getType() {        return this.type;    }    public void setType(String type) {        this.type = type;    }    public String getSource() {        return this.source;    }    public void setSource(String source) {        this.source = source;    }    public String getTitle() {        return this.title;    }    public void setTitle(String title) {        this.title = title;    }    public String getContent() {        return this.content;    }    public void setContent(String content) {        this.content = content;    }    public String getMemo() {        return this.memo;    }    public void setMemo(String memo) {        this.memo = memo;    }    public String getCreator() {        return this.creator;    }    public void setCreator(String creator) {        this.creator = creator;    }    public Timestamp getCreateTime() {        return this.createTime;    }    public void setCreateTime(Timestamp createTime) {        this.createTime = createTime;    }    public String getState() {        return this.state;    }    public void setState(String state) {        this.state = state;    }}

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;

public class Info implements java.io.Serializable {

   private String infoId;
   private String type;
   private String source;
   private String title;
   private String content;
   private String memo;
   private String creator;
   private Timestamp createTime;
   private String state;

   public static String INFO_STATE_PUBLIC = "1";//发布
   public static String INFO_STATE_STOP = "0";//停用

   public static String INFO_TYPE_TZGG = "tzgg";
   public static String INFO_TYPE_ZCSD = "zcsd";
   public static String INFO_TYPE_NSZD = "nszd";

   public static Map<String, String> INFO_TYPE_MAP = new HashMap<String, String>();
   static {
       INFO_TYPE_MAP.put(INFO_TYPE_TZGG, "通知公告");
       INFO_TYPE_MAP.put(INFO_TYPE_ZCSD, "政策速递");
       INFO_TYPE_MAP.put(INFO_TYPE_NSZD, "纳税指导");
   }

   public Info() {
   }

   public Info(String title) {
       this.title = title;
   }

   public Info(String type, String source, String title, String content, String memo, String creator, Timestamp createTime, String state) {
       this.type = type;
       this.source = source;
       this.title = title;
       this.content = content;
       this.memo = memo;
       this.creator = creator;
       this.createTime = createTime;
       this.state = state;
   }


   public String getInfoId() {
       return this.infoId;
   }

   public void setInfoId(String infoId) {
       this.infoId = infoId;
   }

   public String getType() {
       return this.type;
   }

   public void setType(String type) {
       this.type = type;
   }

   public String getSource() {
       return this.source;
   }

   public void setSource(String source) {
       this.source = source;
   }

   public String getTitle() {
       return this.title;
   }

   public void setTitle(String title) {
       this.title = title;
   }

   public String getContent() {
       return this.content;
   }

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

   public String getMemo() {
       return this.memo;
   }

   public void setMemo(String memo) {
       this.memo = memo;
   }

   public String getCreator() {
       return this.creator;
   }

   public void setCreator(String creator) {
       this.creator = creator;
   }

   public Timestamp getCreateTime() {
       return this.createTime;
   }

   public void setCreateTime(Timestamp createTime) {
       this.createTime = createTime;
   }

   public String getState() {
       return this.state;
   }

   public void setState(String state) {
       this.state = state;
   }

}

配置文件

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>    <class name="zhongfucheng.info.entity.Info" table="info">        <id name="infoId" type="java.lang.String">            <column name="info_id" length="32"/>            <generator class="uuid.hex" />        </id>        <property name="type" type="java.lang.String">            <column name="type" length="10" />        </property>        <property name="source" type="java.lang.String">            <column name="source" length="50" />        </property>        <property name="title" type="java.lang.String">            <column name="title" length="100" not-null="true" />        </property>        <property name="content" type="text">            <column name="content" />        </property>        <property name="memo" type="java.lang.String">            <column name="memo" length="200" />        </property>        <property name="creator" type="java.lang.String">            <column name="creator" length="10" />        </property>        <property name="createTime" type="java.sql.Timestamp">            <column name="create_time" length="19" />        </property>        <property name="state" type="java.lang.String">            <column name="state" length="1" />        </property>    </class></hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<hibernate-mapping>
   <class name="zhongfucheng.info.entity.Info" table="info">
       <id name="infoId" type="java.lang.String">
           <column name="info_id" length="32"/>
           <generator class="uuid.hex" />
       </id>
       <property name="type" type="java.lang.String">
           <column name="type" length="10" />
       </property>
       <property name="source" type="java.lang.String">
           <column name="source" length="50" />
       </property>
       <property name="title" type="java.lang.String">
           <column name="title" length="100" not-null="true" />
       </property>
       <property name="content" type="text">
           <column name="content" />
       </property>
       <property name="memo" type="java.lang.String">
           <column name="memo" length="200" />
       </property>
       <property name="creator" type="java.lang.String">
           <column name="creator" length="10" />
       </property>
       <property name="createTime" type="java.sql.Timestamp">
           <column name="create_time" length="19" />
       </property>
       <property name="state" type="java.lang.String">
           <column name="state" length="1" />
       </property>
   </class>
</hibernate-mapping>

常规增删改查

这现在对我们来说没有什么难度了,改之前写过的User模块就行了。

编写dao、编写service、编写action、编写配置文件

将配置文件加载到总配置文件中。

导入前端的JSP页面

弄完之后,简单的增删改查我们已经实现了。。

640?wx_fmt=png
这里写图片描述

接下来就是处理一些不是常用增删改查的东西了。

创建人与创建时间

我们在添加的时候怎么写呢???在需求上,不是让我们填的,而是写死的。

<tr>    <td class="tdBg" width="200px">创建人:</td>    <td>    </td>    <td class="tdBg" width="200px">创建时间:</td>    <td>    </td></tr>
   <td class="tdBg" width="200px">创建人:</td>
   <td>

   </td>
   <td class="tdBg" width="200px">创建时间:</td>
   <td>

   </td>
</tr>

创建人我们在Session中找到对应的用户,给出对应的值。显示出来后,在提交的时候还要通过隐藏域把数据带过去

    <tr>        <td class="tdBg" width="200px">创建人:</td>        <td>            <s:property value="#session.SYS_USER.name"/>            <s:hidden value="#session.SYS_USER.name" name="info.creator"/>        </td>        <td class="tdBg" width="200px">创建时间:</td>        <td>            <s:date name="info.createTime" format="yyyy-MM-dd HH:MM"/>            <s:hidden name="info.createTime"/>        </td>    </tr>
       <td class="tdBg" width="200px">创建人:</td>
       <td>
           <s:property value="#session.SYS_USER.name"/>
           <s:hidden value="#session.SYS_USER.name" name="info.creator"/>
       </td>
       <td class="tdBg" width="200px">创建时间:</td>
       <td>
           <s:date name="info.createTime" format="yyyy-MM-dd HH:MM"/>
           <s:hidden name="info.createTime"/>
       </td>
   </tr>

创建时间,我们可以直接在InfoAction中,new出Info对象,给出对应的值。在JSP页面就可以回显出来了。

当然了,我们也要通过隐藏域把数据带过去。

    public String addUI() {        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);        info = new Info();        info.setCreateTime(new Timestamp(new Date().getTime()));        return "addUI";    }

       ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
       info = new Info();
       info.setCreateTime(new Timestamp(new Date().getTime()));
       return "addUI";
   }

!

640?wx_fmt=png
这里写图片描述

富文本框编辑器

我们想要在那个大文本框中,把复制的内容是带有格式的,图片也可以复制过去。普通的textarea是搞不掂的,我们需要借助别的组件。。我们用的是Ueditor组件

使用步骤:

    "imageUrlPrefix": "http://localhost:8080", /* 图片访问路径前缀 */    "imagePathFormat": "/upload/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */"http://localhost:8080", /* 图片访问路径前缀 */
   "imagePathFormat": "/upload/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
    <script type="text/javascript" charset="utf-8" src="${basePath}js/ueditor/ueditor.config.js"></script>    <script type="text/javascript" charset="utf-8" src="${basePath}js/ueditor/ueditor.all.min.js"> </script>    <script type="text/javascript" charset="utf-8" src="${basePath}js/ueditor/lang/zh-cn/zh-cn.js"></script>    <script>        //配置ueditor的根路径        var UEDITOR_HOME_URL = "${basePath}js/ueditor/";        var ue = UE.getEditor('editor');    </script>"utf-8" src="${basePath}js/ueditor/ueditor.config.js"></script>
   <script type="text/javascript" charset="utf-8" src="${basePath}js/ueditor/ueditor.all.min.js"> </script>
   <script type="text/javascript" charset="utf-8" src="${basePath}js/ueditor/lang/zh-cn/zh-cn.js"></script>
   <script>
       //配置ueditor的根路径
       var UEDITOR_HOME_URL = "${basePath}js/ueditor/";
       var ue = UE.getEditor('editor');
   </script>
    <td colspan="3"><s:textarea id="editor" name="info.content" cssStyle="width:90%;height:160px;" /></td><s:textarea id="editor" name="info.content" cssStyle="width:90%;height:160px;" /></td>

富文本框的配置我们大多数可以在这里修改:

640?wx_fmt=png
这里写图片描述

效果:

640?wx_fmt=png


很奇怪的是,如果单单访问info模块的话,使用是完全没有问题的。但是在总系统进入到info模块时,富文本框就点击不了:输入会显示输入个数,但是显示不了内容。编辑的时候同样看不到内容。

于是在网上搜了一下:把以下的代码加入到要用到富文本框的JSP页面下就解决掉问题了:

<script>    setTimeout(function(){uParse('div',            {                'highlightJsUrl':'/ueditor/third-party/SyntaxHighlighter/shCore.js',                'highlightCssUrl':'/ueditor/third-party/SyntaxHighlighter/shCoreDefault.css'})    },300);</script>function(){uParse('div',
           {
               'highlightJsUrl':'/ueditor/third-party/SyntaxHighlighter/shCore.js',
               'highlightCssUrl':'/ueditor/third-party/SyntaxHighlighter/shCoreDefault.css'})
   },300);
</script>

参考博文:http://blog.youkuaiyun.com/eightwhells/article/details/13314069

异步信息交互

最后地,我们剩下停用与发布这个功能还没完成…

640?wx_fmt=png
这里写图片描述

其实就是一个异步信息交互的实现,当用户点击超链接为停用的时候,就到后台把数据更新,把Info的state变成为0,然后将超链接改成发布。

绑定事件

使用opertor前缀+id定位到我们的span节点中。这肯定是独一无二的。

位于iterator内,直接写state判断就行了。

    <span id="operator_<s:property value='infoId'/>">      <s:if test="state==1">            <a href="javascript:doPublic('<s:property value='infoId'/>',0)">停用</a>        </s:if>        <s:else>            <a href="javascript:doPublic('<s:property value='infoId'/>',1)">发布</a>        </s:else>    </span>
     <s:if test="state==1">
           <a href="javascript:doPublic('<s:property value='infoId'/>',0)">停用</a>
       </s:if>
       <s:else>
           <a href="javascript:doPublic('<s:property value='infoId'/>',1)">发布</a>
       </s:else>
   </span>

ajax进行交互

注意在拼接字符串的时候,不要有空格………

error:如果出错了,可以提示用户。

function doPublic (infoId,state){            $.ajax(                    {                        url: "${basePath}info/info_doPublic.action",                        data: { "info.infoId": infoId,"info.state": state},                        type: "post",                        success: function (backData) {                            if ("更新成功" == backData) {                                if (state == 0) {//如果用户点击的是停用                                    //将超链接改成发布                                    $("#operator_"+infoId).html("<a href='javascript:doPublic(\""+infoId+"\",1)'>发布</a>");                                    //将显示状态改成是停用                                    $("#show_" + infoId).html("停用");                                }else{//用户点击的是发布                                    //将超链接改成停用                                    $("#operator_"+infoId).html("<a href='javascript:doPublic(\""+infoId +"\",0)'>停用</a>");                                    //将显示状态改成是发布                                    $("#show_" + infoId).html("发布");                                }                            }else {                                alert("更新失败,稍后重试");                            }                        },                        //如果失败了,就提示给用户,不要让用户继续操作了                        error:function () {                            alert("更新失败,稍后重试");                        }                    }            );        }    </script>
           $.ajax(
                   {
                       url: "${basePath}info/info_doPublic.action",
                       data: { "info.infoId": infoId,"info.state": state},
                       type: "post",
                       success: function (backData) {

                           if ("更新成功" == backData) {

                               if (state == 0) {//如果用户点击的是停用

                                   //将超链接改成发布
                                   $("#operator_"+infoId).html("<a href='javascript:doPublic(\""+infoId+"\",1)'>发布</a>");

                                   //将显示状态改成是停用
                                   $("#show_" + infoId).html("停用");

                               }else{//用户点击的是发布

                                   //将超链接改成停用
                                   $("#operator_"+infoId).html("<a href='javascript:doPublic(\""+infoId +"\",0)'>停用</a>");

                                   //将显示状态改成是发布
                                   $("#show_" + infoId).html("发布");
                               }

                           }else {
                               alert("更新失败,稍后重试");
                           }
                       },
                       //如果失败了,就提示给用户,不要让用户继续操作了
                       error:function () {
                           alert("更新失败,稍后重试");
                       }

                   }
           );
       }
   </script>

Action处理

得到用户的id,查询出Info对象的信息,再设置Info对象的属性。

    public void doPublic() {        try {            if (info != null) {                //得到用户带过来的id查询出该对象                Info objectById = infoServiceImpl.findObjectById(info.getInfoId());                //设置它的状态                objectById.setState(info.getState());                //调用service更新数据库                infoServiceImpl.update(objectById);                //返回数据给浏览器                HttpServletResponse response = ServletActionContext.getResponse();                response.setContentType("text/html charset=utf-8");                response.getOutputStream().write("更新成功".getBytes("UTF-8"));            }        } catch (IOException e) {            e.printStackTrace();        }    }
       try {

           if (info != null) {
               //得到用户带过来的id查询出该对象
               Info objectById = infoServiceImpl.findObjectById(info.getInfoId());
               //设置它的状态
               objectById.setState(info.getState());

               //调用service更新数据库
               infoServiceImpl.update(objectById);

               //返回数据给浏览器
               HttpServletResponse response = ServletActionContext.getResponse();
               response.setContentType("text/html charset=utf-8");
               response.getOutputStream().write("更新成功".getBytes("UTF-8"));

           }
       } catch (IOException e) {
           e.printStackTrace();
       }


   }

抽取BaseService

到目前为止,我们已经写了三个模块的开发了。我们已经抽取过了BaseAction、BaseDao,我们这次来看看我们的Service接口。

/** * created by ozc on 2017/5/23. */public interface UserService {    //新增    void save(User user);    //更新    void update(User user);    //根据id删除    void delete(Serializable id);    //根据id查找    User findObjectById(Serializable id);    //查找列表    List<User> findObjects() throws ServiceException;    //导出用户列表    void exportExcel(List<User> userList, ServletOutputStream outputStream);    //导入用户列表    void importExcel(File userExcel, String userExcelFileName);    /**     * 根据帐号和用户id查询用户     *     * @param id      用户ID     * @param account 用户帐号     * @return 用户列表     */    List<User> findAccount(String id, String account);    void saveUserAndRole(User user, String[] userRoleIds);    //通过用户id得到该用户的角色    List<UserRole> findRoleById(String id);    void deleteUserRoleById(String[] userRoleIds);    List<User> findUserByAccountAndPassword(String account, String password);}
public interface UserService {

   //新增
   void save(User user);

   //更新
   void update(User user);

   //根据id删除
   void delete(Serializable id);

   //根据id查找
   User findObjectById(Serializable id);

   //查找列表
   List<User> findObjects() throws ServiceException;

   //导出用户列表
   void exportExcel(List<User> userList, ServletOutputStream outputStream);

   //导入用户列表
   void importExcel(File userExcel, String userExcelFileName);

   /**
    * 根据帐号和用户id查询用户
    *
    * @param id      用户ID
    * @param account 用户帐号
    * @return 用户列表
    */

   List<User> findAccount(String id, String account);

   void saveUserAndRole(User user, String[] userRoleIds);

   //通过用户id得到该用户的角色
   List<UserRole> findRoleById(String id);

   void deleteUserRoleById(String[] userRoleIds);

   List<User> findUserByAccountAndPassword(String account, String password);
}
/** * created by ozc on 2017/5/23. */public interface InfoService {    //新增    public void save(Info info);    //更新    public void update(Info info);    //根据id删除    public void delete(Serializable id);    //根据id查找    public Info findObjectById(Serializable id);    //查找列表    public List<Info> findObjects() ;}
public interface InfoService {

   //新增
   public void save(Info info);
   //更新
   public void update(Info info);
   //根据id删除
   public void delete(Serializable id);
   //根据id查找
   public Info findObjectById(Serializable id);
   //查找列表
   public List<Info> findObjects() ;
}
/** * Created by ozc on 2017/5/26. */public interface RoleService {    //新增     void save(Role role);    //更新     void update(Role role);    //根据id删除O     void delete(Serializable id);    //根据id查找     Role findObjectById(Serializable id);    //查找列表     List<Role> findObjects()  ;}
public interface RoleService {

   //新增
    void save(Role role);
   //更新
    void update(Role role);
   //根据id删除O
    void delete(Serializable id);
   //根据id查找
    Role findObjectById(Serializable id);
   //查找列表
    List<Role> findObjects()  ;

}

我们可以发现,三个Service接口中都存在着增删改查的方法,这明显就是重复的代码。因此,我们需要将他们进行抽取成一个BaseService。

抽取BaseService

在core模块中添加service包,抽取BaseService

package zhongfucheng.core.service;import java.io.Serializable;import java.util.List;/** * Created by ozc on 2017/6/7. */interface BaseService<T> {    //新增    void save(T entity);    //更新    void update(T entity);    //根据id删除    void delete(Serializable id);    //根据id查找    T findObjectById(Serializable id);    //查找列表    List<T> findObjects();}

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

/**
* Created by ozc on 2017/6/7.
*/

interface BaseService<T> {
   //新增
   void save(T entity);

   //更新
   void update(T entity);

   //根据id删除
   void delete(Serializable id);

   //根据id查找
   T findObjectById(Serializable id);

   //查找列表
   List<T> findObjects();
}

我们的Sercive是调用dao层的对象来实现方法的,因为这个Service是代表整个项目的Service,于是应该使用BaseDao

package zhongfucheng.core.service.impl;import zhongfucheng.core.dao.BaseDao;import zhongfucheng.core.service.BaseService;import java.io.Serializable;import java.util.List;/** * Created by ozc on 2017/6/7. */public abstract class BaseServiceImpl <T> implements BaseService <T>{    //通过BaseDao来操作数据库    private BaseDao<T> baseDao;    @Override    public void save(T entity) {        baseDao.save(entity);    }    @Override    public void update(T entity) {        baseDao.update(entity);    }    @Override    public void delete(Serializable id) {        baseDao.delete(id);    }    @Override    public T findObjectById(Serializable id) {        return baseDao.findObjectById(id);    }    @Override    public List<T> findObjects() {        return baseDao.findObjects();    }}

import zhongfucheng.core.dao.BaseDao;
import zhongfucheng.core.service.BaseService;

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

/**
* Created by ozc on 2017/6/7.
*/


public abstract class BaseServiceImpl <T> implements BaseService <T>{

   //通过BaseDao来操作数据库
   private BaseDao<T> baseDao;

   @Override
   public void save(T entity) {
       baseDao.save(entity);

   }

   @Override
   public void update(T entity) {
       baseDao.update(entity);

   }

   @Override
   public void delete(Serializable id) {
       baseDao.delete(id);

   }
   @Override
   public T findObjectById(Serializable id) {
       return baseDao.findObjectById(id);
   }

   @Override
   public List<T> findObjects() {
       return baseDao.findObjects();

   }
}

以Info模块举例子

InfoService继承了BaseService接口,于是就有了增删改查的方法。同时把泛型T的类型确定下来。

    /**     * created by ozc on 2017/5/23.     */    public interface InfoService extends BaseService<Info> {    }
   public interface InfoService extends BaseService<Info> {

   }

继承了InfoService,有了增删该查的方法,然而具体的操作是BaseServiceImpl中实现的。我们继承它,并给出泛型T对应的类型。

@Servicepublic class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService {}
public class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService {


}

现在的问题是什么呢???我们在BaseServiceImpl中使用了BaseDao这个变量来对数据库进行操作。可是在BaseServiceImpl中是没有BaseDao这个变量的。

首先,要明确的是,我们不能在BaseServiceImpl中注入BaseDao,因为BaseServiceImpl本身就是一个抽象类。那我们怎么对BaseDao进行实例化呢???

我们可以这样做:

@Servicepublic class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService {    private InfoDao infoDao;    @Resource    public void setInfoDao(InfoDao infoDao) {        super.setBaseDao(infoDao);        this.infoDao = infoDao;    }}
public class InfoServiceImpl extends BaseServiceImpl<Info> implements InfoService {

   private InfoDao infoDao;
   @Resource
   public void setInfoDao(InfoDao infoDao) {
       super.setBaseDao(infoDao);
       this.infoDao = infoDao;
   }
}
   //通过BaseDao来操作数据库    private BaseDao<T> baseDao;    public void setBaseDao(BaseDao<T> baseDao) {        this.baseDao = baseDao;    }
   private BaseDao<T> baseDao;
   public void setBaseDao(BaseDao<T> baseDao) {
       this.baseDao = baseDao;
   }

条件查询

我们来实现下面的功能:

640?wx_fmt=png
这里写图片描述

传统方式

其实也是一个查询,只不过查询多了一个条件罢了。按照传统的方式我们可以这样做:

    //根据条件查询列表    List<T> findObjects(String sql, List<Object> objectList);
   List<T> findObjects(String sql, List<Object> objectList);
    @Override    public List<T> findObjects(String sql, List<Object> objectList) {        Query query = getSession().createQuery(sql);        if (objectList != null) {            int i =0;            for (Object o : objectList) {                query.setParameter(i, o);                i++;            }            return query.list();        }        return query.list();    }
   public List<T> findObjects(String sql, List<Object> objectList) {

       Query query = getSession().createQuery(sql);
       if (objectList != null) {
           int i =0;
           for (Object o : objectList) {
               query.setParameter(i, o);
               i++;
           }
           return query.list();
       }
       return query.list();
   }
    //根据条件查询列表    List<T> findObjects(String sql, List<Object> objectList);
   List<T> findObjects(String sql, List<Object> objectList);
    @Override    public List<T> findObjects(String sql, List<Object> objectList) {        return baseDao.findObjects(sql, objectList);    }
   public List<T> findObjects(String sql, List<Object> objectList) {
       return baseDao.findObjects(sql, objectList);
   }

我们还是用着listUI这个方法,因为它仅仅是参数可能不同。

    public String listUI() {        //查询语句        String hql = "FROM Info i ";        List<Object> objectList  = new ArrayList<>();        //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。        if (info != null) {            if (StringUtils.isNotBlank(info.getTitle())) {                hql += "where i.title like ?";                objectList.add("%" + info.getTitle() + "%");            }        }        infoList = infoServiceImpl.findObjects(hql,objectList);        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);        return "listUI";    }

       //查询语句
       String hql = "FROM Info i ";
       List<Object> objectList  = new ArrayList<>();

       //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。
       if (info != null) {
           if (StringUtils.isNotBlank(info.getTitle())) {
               hql += "where i.title like ?";
               objectList.add("%" + info.getTitle() + "%");
           }
       }
       infoList = infoServiceImpl.findObjects(hql,objectList);
       ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
       return "listUI";
   }

优化

看回我们Action中的代码,我们可以看出一些不够优雅的地方:

640?wx_fmt=png
这里写图片描述

于是,我们想要用一个工具类来把上面的代码进行优化。

针对上面的问题,我们发现手写拼接SQL很容易出错。那我们可以在工具类里面拼接,使用的时候调用方法获取就行啦。查询的对象写死了,我们要可以处理任何的查询。

我们能够找到如下的规律:

    FROM Info     WHERE title like ? and state = ?     order by createTime,state    条件查询(QueryHelper):    1、查询条件语句hql:    from 子句:必定出现;而且只出现一次    where 子句:可选;但关键字where 出现一次;可添加多个查询条件    order by子句:可选;但关键字order by 出现一次;可添加多个排序属性    2、查询条件值集合:    出现时机:在添加查询条件的时候,?对应的查询条件值
   order by createTime,state


   条件查询(QueryHelper):

   1、查询条件语句hql:
   from 子句:必定出现;而且只出现一次
   where 子句:可选;但关键字where 出现一次;可添加多个查询条件
   order by子句:可选;但关键字order by 出现一次;可添加多个排序属性

   2、查询条件值集合:
   出现时机:在添加查询条件的时候,?对应的查询条件值
package zhongfucheng.core.utils;import java.util.ArrayList;import java.util.List;/** * Created by ozc on 2017/6/7. */public class QueryHelper {    private String fromClause = "";    private String whereClause = "";    private String orderbyClause = "";    private List<Object> objectList;    public static String ORDER_BY_ASC = "asc";    public static String ORDER_BY_DESC = "desc";    //FROM子句只出现一次    /**     * 构建FROM字句,并设置查询哪张表     * @param aClass 用户想要操作的类型     * @param alias  别名     */    public QueryHelper(Class aClass, String alias) {        fromClause = "  FROM " + aClass.getSimpleName() + "  " + alias;    }    //WHERE字句可以添加多个条件,但WHERE关键字只出现一次    /**     * 构建WHERE字句     * @param condition     * @param objects     * @return     */    public QueryHelper addCondition(String condition, Object... objects) {        //如果已经有字符了,那么就说明已经有WHERE关键字了        if (whereClause.length() > 0) {            whereClause += " AND  " + condition;        } else {            whereClause += " WHERE" + condition;        }        //在添加查询条件的时候,?对应的查询条件值        if (objects == null) {            objectList = new ArrayList<>();        }        for (Object object : objects) {            objectList.add(object);        }        return this;    }    /**     *     * @param property 要排序的属性     * @param order 是升序还是降序     * @return     */    public QueryHelper orderBy(String property, String order) {        //如果已经有字符了,那么就说明已经有ORDER关键字了        if (orderbyClause.length() > 0) {            orderbyClause += " ,  " + property +"   " + order;        } else {            orderbyClause += "  ORDER BY " + property+"   " + order;        }        return this;    }    /**     * 返回HQL语句     */    public String returnHQL() {        return fromClause + whereClause + orderbyClause;    }    /**     * 得到参数列表     * @return     */    public List<Object> getObjectList() {        return objectList;    }}

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

/**
* Created by ozc on 2017/6/7.
*/

public class QueryHelper {

   private String fromClause = "";
   private String whereClause = "";
   private String orderbyClause = "";
   private List<Object> objectList;

   public static String ORDER_BY_ASC = "asc";
   public static String ORDER_BY_DESC = "desc";



   //FROM子句只出现一次
   /**
    * 构建FROM字句,并设置查询哪张表
    * @param aClass 用户想要操作的类型
    * @param alias  别名
    */

   public QueryHelper(Class aClass, String alias) {
       fromClause = "  FROM " + aClass.getSimpleName() + "  " + alias;
   }
   //WHERE字句可以添加多个条件,但WHERE关键字只出现一次
   /**
    * 构建WHERE字句
    * @param condition
    * @param objects
    * @return
    */

   public QueryHelper addCondition(String condition, Object... objects) {
       //如果已经有字符了,那么就说明已经有WHERE关键字了
       if (whereClause.length() > 0) {
           whereClause += " AND  " + condition;
       } else {
           whereClause += " WHERE" + condition;
       }
       //在添加查询条件的时候,?对应的查询条件值
       if (objects == null) {
           objectList = new ArrayList<>();
       }

       for (Object object : objects) {
           objectList.add(object);
       }

       return this;
   }
   /**
    *
    * @param property 要排序的属性
    * @param order 是升序还是降序
    * @return
    */

   public QueryHelper orderBy(String property, String order) {

       //如果已经有字符了,那么就说明已经有ORDER关键字了
       if (orderbyClause.length() > 0) {
           orderbyClause += " ,  " + property +"   " + order;
       } else {
           orderbyClause += "  ORDER BY " + property+"   " + order;
       }
       return this;
   }

   /**
    * 返回HQL语句
    */

   public String returnHQL() {
       return fromClause + whereClause + orderbyClause;
   }

   /**
    * 得到参数列表
    * @return
    */

   public List<Object> getObjectList() {
       return objectList;
   }
}
    public String listUI() {        QueryHelper queryHelper = new QueryHelper(Info.class, "i");        //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。        if (info != null) {            if (StringUtils.isNotBlank(info.getTitle())) {                queryHelper.addCondition(" i.title like ? ", "%" + info.getTitle() + "%");            }        }        queryHelper.orderBy("i.createTime", QueryHelper.ORDER_BY_DESC);        infoList = infoServiceImpl.findObjects(queryHelper);        //infoList = infoServiceImpl.findObjects(hql,objectList);        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);        return "listUI";    }

       QueryHelper queryHelper = new QueryHelper(Info.class, "i");

       //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。
       if (info != null) {
           if (StringUtils.isNotBlank(info.getTitle())) {
               queryHelper.addCondition(" i.title like ? ", "%" + info.getTitle() + "%");
           }
       }
       queryHelper.orderBy("i.createTime", QueryHelper.ORDER_BY_DESC);

       infoList = infoServiceImpl.findObjects(queryHelper);

       //infoList = infoServiceImpl.findObjects(hql,objectList);
       ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
       return "listUI";
   }

数据回显

前面我们已经完成了条件查询的功能,可以根据用户给出的条件进行查询数据。但是呢,还是有一些小毛病的。我们来看看:

640?wx_fmt=gif
这里写图片描述

当我们查询数据时候,对查询出来的数据进行操作。操作完毕后,它回到的不是我们查询后的数据,而是我们的初始化数据。这明显是不合适的,当用户操作完后,我们应该返回的还是条件查询出来的数据

还有一点的就是:我们的分页还没写……因此,下面主要解决这两个问题。

首先,我们来分析一下为什么我们操作完毕后,得到的是初始化的数据。我们按照用户的操作来看看到底哪里出了问题。

  1. 用户按条件查询数据,显示查询后的数据

  2. 用户点击编辑/删除对查询后的数据操作,交给Action处理

  3. Action返回给显示页面jsp

  4. JSP页面提交请求到Action中,Action进行处理

  5. 最后Action重定向到listUI

那么在这个过程,我们遇到什么问题呢???

640?wx_fmt=png
这里写图片描述

处理1.0

在Action中使用一个变量封装着查询条件

    /************获取查询条件的值*************************/    private String selectCondition;    public String getSelectCondition() {        return selectCondition;    }    public void setSelectCondition(String selectCondition) {        this.selectCondition = selectCondition;    }
   private String selectCondition;
   public String getSelectCondition() {
       return selectCondition;
   }
   public void setSelectCondition(String selectCondition) {
       this.selectCondition = selectCondition;
   }

当请求到Action时,我们将查询条件的值取出来,发给对应的JSP页面

    public String editUI() {        //得到所有的信息类型        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);        //外边已经传了id过来了,我们要找到id对应的Info        if (info != null && info.getInfoId() != null) {            //把查询条件发给JSP页面            ActionContext.getContext().getContextMap().put("selectCondition", info.getTitle());            //直接获取出来,后面JSP会根据Info有getter就能读取对应的信息!            info = infoServiceImpl.findObjectById(info.getInfoId());        }        return "editUI";    }

       //得到所有的信息类型
       ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
       //外边已经传了id过来了,我们要找到id对应的Info
       if (info != null && info.getInfoId() != null) {

           //把查询条件发给JSP页面
           ActionContext.getContext().getContextMap().put("selectCondition", info.getTitle());

           //直接获取出来,后面JSP会根据Info有getter就能读取对应的信息!
           info = infoServiceImpl.findObjectById(info.getInfoId());

       }
       return "editUI";
   }

JSP页面把发送过来的值存储好,通过隐藏域发送给Action

    <%--把查询条件带过去给Action--%>    <s:hidden name="selectCondition"/>
   <s:hidden name="selectCondition"/>

重新抵达到Action的时候,由于Struts2有自动封装的功能,所以可以把查询条件封装到selectCondition变量中。最后操作完重定向到listUI界面

由于是重定向,所以我们需要在struts配置文件中把我们的查询条件带过去:

    <result name="list" type="redirectAction">        <param name="actionName">info_listUI</param>        <!--重定向回去的时候,把查询条件带上-->        <param name="info.title">${selectCondition}</param>    </result>
       <param name="actionName">info_listUI</param>

       <!--重定向回去的时候,把查询条件带上-->
       <param name="info.title">${selectCondition}</param>
   </result>

当然啦,在删除的时候,把查询条件记录下来就行了。

    //删除    public String delete() {        selectCondition = info.getTitle();        String id = info.getInfoId();        infoServiceImpl.delete(id);        return "list";    }
   public String delete() {
       selectCondition = info.getTitle();
       String id = info.getInfoId();
       infoServiceImpl.delete(id);
       return "list";
   }


处理2.0

上面我们的确解决了查询后数据回显的情况,但是如果我们的查询条件是中文的话,会怎么样??

640?wx_fmt=png
这里写图片描述

变成了乱码了…..在解决它之前,我们又来分析一下为什么出现乱码了….

        <!--传输数据的时候需要编码-->        <param name="encode">true</param>
       <param name="encode">true</param>
    if (info != null) {        if (StringUtils.isNotBlank(info.getTitle())) {            selectCondition =  URLDecoder.decode(info.getTitle(),"UTF-8");            info.setTitle(selectCondition);            queryHelper.addCondition(" i.title like ? ", "%" + info.getTitle() + "%");        }    }null) {
       if (StringUtils.isNotBlank(info.getTitle())) {
           selectCondition =  URLDecoder.decode(info.getTitle(),"UTF-8");
           info.setTitle(selectCondition);

           queryHelper.addCondition(" i.title like ? ", "%" + info.getTitle() + "%");
       }
   }

分页

分页对我们来说也不是陌生的事情了,我曾经在写JDBC博文的时候就讲解过分页了:http://blog.youkuaiyun.com/hon_3y/article/details/53790092

分页的复用代码http://blog.youkuaiyun.com/hon_3y/article/details/70051541

我们这一次还是使用回我们的分页复用代码,具体不同的需求,在上面修改即可了。

在dao和daoImpl中添加方法

    /**     *     * @param queryHelper 查询助手,条件查询都交给查询助手来干     * @param currentPage 当前页数     * @return     */    PageResult getPageResult(QueryHelper queryHelper, int currentPage);
   PageResult getPageResult(QueryHelper queryHelper, int currentPage);
    /**     *     * @return 返回查询总记录数的sql语句     */    public String getTotalRecordSql() {        return "SELECT COUNT(*) " + fromClause + whereClause;    }
   public String getTotalRecordSql() {
       return "SELECT COUNT(*) " + fromClause + whereClause;
   }
    public PageResult getPageResult(QueryHelper queryHelper, int currentPage) {        //查询总记录数        Query queryCount = getSession().createQuery(queryHelper.getTotalRecordSql());        if (queryHelper.getObjectList() != null) {            int i =0;            for (Object o : queryHelper.getObjectList()) {                queryCount.setParameter(i, o);                i++;            }        }        Long totalRecord = (Long) queryCount.uniqueResult();        //初始化PageResult对象        PageResult pageResult = new PageResult(currentPage, totalRecord);        //查询具体模块的数据【有查询条件的也可以处理】        Query query = getSession().createQuery(queryHelper.returnHQL());        if (queryHelper.getObjectList() != null) {            int i =0;            for (Object o : queryHelper.getObjectList()) {                query.setParameter(i, o);                i++;            }        }        //设置分页开始和末尾        query.setFirstResult(pageResult.getStartIndex());        query.setMaxResults(pageResult.getLineSize());        List dataList = query.list();        //将条件查询出来的数据设置到Page对象中        pageResult.setList(dataList);        return pageResult;    }

       //查询总记录数
       Query queryCount = getSession().createQuery(queryHelper.getTotalRecordSql());
       if (queryHelper.getObjectList() != null) {
           int i =0;
           for (Object o : queryHelper.getObjectList()) {
               queryCount.setParameter(i, o);
               i++;
           }
       }
       Long totalRecord = (Long) queryCount.uniqueResult();

       //初始化PageResult对象
       PageResult pageResult = new PageResult(currentPage, totalRecord);

       //查询具体模块的数据【有查询条件的也可以处理】
       Query query = getSession().createQuery(queryHelper.returnHQL());
       if (queryHelper.getObjectList() != null) {
           int i =0;
           for (Object o : queryHelper.getObjectList()) {
               query.setParameter(i, o);
               i++;
           }
       }


       //设置分页开始和末尾
       query.setFirstResult(pageResult.getStartIndex());
       query.setMaxResults(pageResult.getLineSize());
       List dataList = query.list();

       //将条件查询出来的数据设置到Page对象中
       pageResult.setList(dataList);
       return pageResult;
   }

在service和serviceImpl中添加方法

    PageResult getPageResult(QueryHelper queryHelper, int currentPage);
    public PageResult getPageResult(QueryHelper queryHelper, int currentPage) {        return baseDao.getPageResult(queryHelper, currentPage);    }
       return baseDao.getPageResult(queryHelper, currentPage);
   }

在Action中调用service的方法

设置我们需要用到的分页属性。

    private int currentPageCount;    private PageResult pageResult;    public int getCurrentPageCount() {        return currentPageCount;    }    public void setCurrentPageCount(int currentPageCount) {        this.currentPageCount = currentPageCount;    }    public PageResult getPageResult() {        return pageResult;    }    public void setPageResult(PageResult pageResult) {        this.pageResult = pageResult;    }int currentPageCount;
   private PageResult pageResult;
   public int getCurrentPageCount() {
       return currentPageCount;
   }
   public void setCurrentPageCount(int currentPageCount) {
       this.currentPageCount = currentPageCount;
   }
   public PageResult getPageResult() {
       return pageResult;
   }
   public void setPageResult(PageResult pageResult) {
       this.pageResult = pageResult;
   }

判断我们的当前页是否为0【如果为0,就代表着刚初始化值,我们设置为1】,调用service的方法得到分页对象

    //当前页数没有值,那么赋值为1    if (currentPageCount == 0) {        currentPageCount = 1;    }    pageResult = infoServiceImpl.getPageResult(queryHelper,currentPageCount);
   if (currentPageCount == 0) {
       currentPageCount = 1;
   }
   pageResult = infoServiceImpl.getPageResult(queryHelper,currentPageCount);

在JSP页面中,我们遍历分页对象的集合就可以获取分页的数据了。

   <s:iterator value="pageResult.list" status="st">

抽取属性

我们的分页属性和查询条件数据不单单只有Info模块用的,于是我们将分页数据抽取到BaseAction中

    /************分页属性*************************/    protected int currentPageCount;    protected PageResult pageResult;    public int getCurrentPageCount() {        return currentPageCount;    }    public void setCurrentPageCount(int currentPageCount) {        this.currentPageCount = currentPageCount;    }    public PageResult getPageResult() {        return pageResult;    }    public void setPageResult(PageResult pageResult) {        this.pageResult = pageResult;    }    /************获取查询条件的值*************************/    protected String selectCondition;    public String getSelectCondition() {        return selectCondition;    }    public void setSelectCondition(String selectCondition) {        this.selectCondition = selectCondition;    }
   protected int currentPageCount;
   protected PageResult pageResult;
   public int getCurrentPageCount() {
       return currentPageCount;
   }
   public void setCurrentPageCount(int currentPageCount) {
       this.currentPageCount = currentPageCount;
   }
   public PageResult getPageResult() {
       return pageResult;
   }
   public void setPageResult(PageResult pageResult) {
       this.pageResult = pageResult;
   }

   /************获取查询条件的值*************************/
   protected String selectCondition;
   public String getSelectCondition() {
       return selectCondition;
   }
   public void setSelectCondition(String selectCondition) {
       this.selectCondition = selectCondition;
   }

修改其他的模块,也能够拥有条件查询和分页查询这两个功能:以用户模块为例。

    //抛出Action异常    public String listUI() throws ServiceException, UnsupportedEncodingException {        QueryHelper queryHelper = new QueryHelper(User.class, "u");        //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。        if (user != null) {            if (org.apache.commons.lang.StringUtils.isNotBlank(user.getName())) {                selectCondition =  URLDecoder.decode(user.getName(),"UTF-8");                user.setName(selectCondition);                queryHelper.addCondition(" u.name like ? ", "%" + user.getName() + "%");            }        }        //当前页数没有值,那么赋值为1        if (currentPageCount == 0) {            currentPageCount = 1;        }        pageResult = userServiceImpl.getPageResult(queryHelper,currentPageCount);        return "listUI";    }
   public String listUI() throws ServiceException, UnsupportedEncodingException {
       QueryHelper queryHelper = new QueryHelper(User.class, "u");
       //根据info是否为null来判断是否是条件查询。如果info为空,那么是查询所有。
       if (user != null) {
           if (org.apache.commons.lang.StringUtils.isNotBlank(user.getName())) {
               selectCondition =  URLDecoder.decode(user.getName(),"UTF-8");
               user.setName(selectCondition);
               queryHelper.addCondition(" u.name like ? ", "%" + user.getName() + "%");
           }
       }
       //当前页数没有值,那么赋值为1
       if (currentPageCount == 0) {
           currentPageCount = 1;
       }
       pageResult = userServiceImpl.getPageResult(queryHelper,currentPageCount);
       return "listUI";
   }
        <s:iterator value="pageResult.list">          <jsp:include page="/common/pageNavigator.jsp"/>
         <jsp:include page="/common/pageNavigator.jsp"/>

处理查询后数据回显的问题:

    public String editUI() {        //把所有的角色查询出来,带过去给JSP页面显示        ActionContext.getContext().getContextMap().put("roleList", roleServiceImpl.findObjects());        //外边已经传了id过来了,我们要找到id对应的User        if (user != null &&user.getId() != null  ) {            //得到查询条件            selectCondition = user.getName();            //直接获取出来,后面JSP会根据User有getter就能读取对应的信息!            user = userServiceImpl.findObjectById(user.getId());            //通过用户的id得到所拥有UserRole            List<UserRole> roles = userServiceImpl.findRoleById(user.getId());            //把用户拥有角色的id填充到数组中,数组最后回显到JSP页面            int i=0;            userRoleIds =  new String[roles.size()];            for (UserRole role : roles) {                userRoleIds[i++] = role.getUserRoleId().getRole().getRoleId();            }        }        return "editUI";    }

       //把所有的角色查询出来,带过去给JSP页面显示
       ActionContext.getContext().getContextMap().put("roleList", roleServiceImpl.findObjects());

       //外边已经传了id过来了,我们要找到id对应的User
       if (user != null &&user.getId() != null  ) {

           //得到查询条件
           selectCondition = user.getName();

           //直接获取出来,后面JSP会根据User有getter就能读取对应的信息!
           user = userServiceImpl.findObjectById(user.getId());

           //通过用户的id得到所拥有UserRole
           List<UserRole> roles = userServiceImpl.findRoleById(user.getId());
           //把用户拥有角色的id填充到数组中,数组最后回显到JSP页面
           int i=0;
           userRoleIds =  new String[roles.size()];
           for (UserRole role : roles) {
               userRoleIds[i++] = role.getUserRoleId().getRole().getRoleId();
           }

       }
       return "editUI";
   }
    <%--把查询条件通过隐藏域带过去给Action--%>    <s:hidden name="selectCondition"></s:hidden>
   <s:hidden name="selectCondition"></s:hidden>
        <action name="user_*" class="zhongfucheng.user.action.UserAction" method="{1}">            <result name="{1}" >/WEB-INF/jsp/user/{1}.jsp</result>            <!--返回列表展示页面,重定向到列表展示-->            <result name="list" type="redirectAction">                <param name="actionName">user_listUI</param>                <param name="user.name">${selectCondition}</param>                <param name="encode">true</param>            </result>        </action>
           <result name="{1}" >/WEB-INF/jsp/user/{1}.jsp</result>

           <!--返回列表展示页面,重定向到列表展示-->
           <result name="list" type="redirectAction">
               <param name="actionName">user_listUI</param>
               <param name="user.name">${selectCondition}</param>
               <param name="encode">true</param>
           </result>
       </action>
    //删除    public String delete() {        if (user != null && user.getId() != null) {            //记载着查询条件            selectCondition = user.getName();            userServiceImpl.delete(user.getId());        }        return "list";    }
   public String delete() {
       if (user != null && user.getId() != null) {

           //记载着查询条件
           selectCondition = user.getName();

           userServiceImpl.delete(user.getId());
       }
       return "list";
   }

总结

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值