ProductTypeAction.java
package com.charlie.shop.view.action;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.charlie.shop.domain.page.Page;
import com.charlie.shop.domain.product.ProductType;
import com.charlie.shop.util.HqlHelper;
import com.charlie.shop.util.URLUtils;
import com.opensymphony.xwork2.ActionContext;
@Controller
@Scope("prototype")
public class ProductTypeAction extends BaseAction<ProductType> {
/** 当前页码,用于分页,默认是1 */
private int pageNow = 1;
/** 上级分类的id号 */
private Long parentId;
/** 查询标志,query为true,表示是查询请求,否则为简单的列表功能 */
private Boolean query;
/** 跳转路径*/
private static String urlAddress = URLUtils.getURL("product.type.list");
/**
* 列表(在这里有两个作用,一是简单地用作列表显示,二是还可以用以查询)
* 功能一:列表功能,主要是分页显示所有的顶级类别或者某一个类别的下级类别
* 准备数据,默认一进列表页时,显示的是最顶级的分类,当点击分类名称时才显示其下级分类列表
* 我们可以通过判断请求中传来的parentId,如果为空,则表示请求的是列表首页,要显示所有最顶级的分类即可
* 如果parentId不为空,则显示这个id号对应的分类的直接下级分类
* 分页显示
* 功能二:查询,根据名称来查询
*/
public String list() {
//创建HqlHelper对象,ProductType类具有visible属性,所以第三个参数为true
HqlHelper hqlHelper = new HqlHelper("ProductType", "p", true);
//判断是否是查询请求
if(query!=null&&query){//查询请求
//先判断查询名称是否为空
if(model.getName()==null||model.getName().trim().equals("")){
request.put("message", "查询类别不能为空");
request.put("urlAddress", urlAddress);
return "message";
}else{//查询类别名称不为空,合法
hqlHelper.setCondition("p.name like ?", "%"+model.getName().trim()+"%");
}
}else{//列表请求
if(parentId==null||parentId==0){
//显示顶级分类
hqlHelper.setCondition("p.parent is null");//这句一定要加
}else{
//显示下级分类
hqlHelper.setCondition("p.parent.id=?", parentId);
}
}
//调用service的getByPage()方法获取分页实体
Page<ProductType> page = productTypeService.getByPage(pageNow, hqlHelper);
/*
* hibernate是默认懒加载的,在jsp页面中查询每个ProductType的children时会报异常
* 解决方法:
* 方法1、在web.xml中添加OpensessionInViewFilter过滤器,这个过滤器起到延时关闭session的作用
* 方法2、在需要的地方手动查询,这里使用了方法二
*/
for(ProductType pt : page.getRecordList()){
List<ProductType> childList = productTypeService.getChildren(pt.getId());
Set<ProductType> childSet = new HashSet<ProductType>(childList);
pt.setChildren(childSet);
}
//把page放到valueStack
ActionContext.getContext().getValueStack().push(page);
//request.put("parentId",parentId);
return "list";
}
/**
* 类别添加页面
*/
public String addUI(){
return "addUI";
}
/**
* 添加类别
*/
public String add(){
//检验类别名称是否为空
if(model.getName()==null||model.getName().trim().equals("")){
//类别名称为空,属于非法
request.put("message", "类别名称不能为空");
}else{//类别名称不为空,合法
//判断父类id
if(parentId!=null&&parentId>0){//添加的不是顶级类别
ProductType parent = productTypeService.getById(parentId);
//设置父类
model.setParent(parent);
}
productTypeService.save(model);
request.put("message", "新类别增加成功");
}
//设置跳转路径
request.put("urlAddress", urlAddress);
return "message";
}
/**
* 类别修改页面
*/
public String editUI(){
//准备数据
ProductType pt = productTypeService.getById(model.getId());
model.setName(pt.getName());
model.setDescript(pt.getDescript());
return "editUI";
}
/**
* 修改类别
*/
public String edit(){
/**
* 注意:修改时不能直接 productTypeService.update(model);
* 应该分三步:
* 1、从数据库中取出对象
* 2、对数据库中取出的对象需要修改的属性用model对应的属性去设置
* 3、更新
*/
if(model.getName()==null||model.getName().trim().equals("")){
//类别名称为空,属于非法
request.put("message", "类别名称不能为空");
}else{
// 1、从数据库中取出原对象
ProductType pt = productTypeService.getById(model.getId());
// 2、设置要修改的属性
pt.setName(model.getName());
pt.setDescript(model.getDescript());
// 3、更新到数据库
productTypeService.update(pt);
request.put("message", "类别修改成功");
}
//设置跳转路径
request.put("urlAddress", urlAddress);
return "message";
}
/**
* 类别查询页面
*/
public String queryUI(){
return "queryUI";
}
// ----------getter/setter方法-------------------
public int getPageNow() {
return pageNow;
}
public void setPageNow(int pageNow) {
this.pageNow = pageNow;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public Boolean getQuery() {
return query;
}
public void setQuery(Boolean query) {
this.query = query;
}
}
ProductTypeServiceImpl.java
package com.charlie.shop.service.impl;
import java.util.List;
import org.hibernate.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.charlie.shop.dao.base.BaseDaoImpl;
import com.charlie.shop.domain.product.ProductType;
import com.charlie.shop.service.ProductTypeService;
@Service("productTypeService")
@Transactional
public class ProductTypeServiceImpl extends BaseDaoImpl<ProductType> implements ProductTypeService{
/**
* 重写删除方法,删除时并不真正做物理删除,只是设为不可见即可。
* 思路:利用hql语句 update ProductType t set t.visible=? where t.id in (?,?,?,?)
* 上面hql语句中最后部分(?,?,?,?),问号个数决定于形参ids的长度
*/
@Override
public void delete(Long... ids) {
if(ids==null||ids.length==0){
return;
}
StringBuffer hql = new StringBuffer();
//拼接hql语句
hql.append("update ProductType t set t.visible=? where t.id in (");
for(int i =0;i<ids.length;i++){
if(i<ids.length-1){
hql.append("?,");
}else{
hql.append("?)");
}
}
//创建Query对象
Query query = getSession().createQuery(hql.toString());
//设置Query的参数
query.setBoolean(0, false);
for(int i=1;i<=ids.length;i++){
query.setLong(i, ids[i-1]);
}
//执行hql
query.executeUpdate();
}
@SuppressWarnings("unchecked")
@Override
public List<ProductType> getChildren(Long id) {
ProductType pt = null;//当前类别
List<ProductType> children = null;//子类别集合
pt = this.getById(id);
if(pt!=null){//要确保当前类别存在
//拼接hql语句
StringBuffer hql = new StringBuffer();
hql.append("FROM ProductType p WHERE p.parent=?");
//创建Query对象
Query query = getSession().createQuery(hql.toString());
//设置参数
query.setParameter(0, pt);
//查询
children = query.list();
}
return children;
}
}
注意:
1、用户在页面中填写的内容可能含有前后空格,在接受并设置为实体属性值时应该去掉前后空格,在类别实体中,有name,descript这两个String类型的属性,需要重写setter方法,如下:
public void setName(String name) {
//要去掉形参前后的空格
this.name = name==null?null:name.trim();
}
public void setDescript(String descript) {
//要去掉形参前后的空格
this.descript = descript==null?null:descript.trim();
}
2、在列表页面中,form表单里要添加以下隐藏字段:
<input type="hidden" name="query" value="${query}" />
<input type="hidden" name="parentId" value="${parentId}" />
<input type="hidden" name="name" value="${name}" />
(1)query字段主要是用于区分是查询请求还是列表请求;
(2)parentId字段主要是用于列表请求,当某个类别的下级类别数量较多超过一页时,就要分页显示,当点击某个页码时,有了parentId字段也就可以传父类id给action,否则action会以为请求的是顶级类别
(3)name字段主要是用于查询请求,道理和parentId字段类似,也是解决分页存在的bug