基于springboot jpa thymeleaf的java无限分类的样式及表格创建见:
http://www.ncyteng.com/news/show/866.html
一. 建立实体文件如下:
@Entity
public class Sorts {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String sortName;
private int parentId;
private String sortPath;
private int levels;
private int orders;
@Transient
private String space; //列表查询时, 前面的空间隔
@Transient
private String oldSortPath;
@Transient
private String newSortPath;
public String getSortName() {
return sortName;
}
public void setSortName(String sortName) {
this.sortName = sortName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getParentId() {
return parentId;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}
public String getSortPath() {
return sortPath;
}
public void setSortPath(String sortPath) {
this.sortPath = sortPath;
}
public int getLevels() {
return levels;
}
public void setLevels(int levels) {
this.levels = levels;
}
public int getOrders() {
return orders;
}
public void setOrders(int orders) {
this.orders = orders;
}
public String getSpace() {
return space;
}
public void setSpace(String space) {
this.space = space;
}
public String getOldSortPath() {
return oldSortPath;
}
public void setOldSortPath(String oldSortPath) {
this.oldSortPath = oldSortPath;
}
public String getNewSortPath() {
return newSortPath;
}
public void setNewSortPath(String newSortPath) {
this.newSortPath = newSortPath;
}
}二. 建立Resotitory接口
public interface SortsRepository extends JpaRepository<Sorts,Integer>, JpaSpecificationExecutor<Sorts> {
@Query(value=" select * from sorts where parentId = ?1 order by orders asc ",nativeQuery=true )
public ArrayList<Sorts> selectByParentId(Integer id) ;
@Query(value="select * from sorts where parentId = :#{#sorts.parentId} and sortName = :#{#sorts.sortName}",nativeQuery=true )
public Sorts selectBySortNameAndParendId(@Param("sorts") Sorts sorts);
@Query(value = " select * from sorts where parentId = :#{#sorts.parentId} and sortName = :#{#sorts.sortName} " +
"and id <> :#{#sorts.id}",nativeQuery = true)
public Sorts selectSortsByParentIdSortName(@Param("sorts") Sorts sorts);
@Query(value = " update sorts set sortPath = replace(sortPath,:#{#sorts.oldSortPath},:#{#sorts.newSortPath}) where\n" +
" sortPath like concat('%',:#{#sorts.oldSortPath},'%') and id <> :#{#sorts.id}",
nativeQuery = true)
@Transactional
@Modifying
public int updateAllChildSorts(@Param("sorts")Sorts sorts);
@Query(value = " update sorts set levels = length(sortPath)- length(replace(sortPath,',','')) - 1 where\n" +
" sortPath like concat('%',:#{#sorts.newSortPath},'%') and id <> :#{#sorts.id}",
nativeQuery = true)
@Transactional
@Modifying
public int updateAllChildSortsLevels(@Param("sorts")Sorts sorts);
@Query(value = "delete from sorts where sortPath like concat ('%',','+ :id +',','%')",
nativeQuery = true)
@Transactional
@Modifying
public int deleteAllSortsById(@Param("id") Integer id);
}三. 建立service接口
public interface SortsService {
public ArrayList<Sorts> getChildren(int parentId, String space, ArrayList<Sorts> arr);
public StringBuffer selectTrees(int pid,String selectName,int currentId);
public String addSorts(Sorts sorts);
public String updateSorts(Sorts sorts);
public String deleteAllSortsById(Integer id);
}四. 实现SortsService接口类
@Service("sortsService")
public class SortsServiceImpl implements SortsService {
@Autowired
private SortsRepository sortsDao;
private static ArrayList<Sorts> all; //存储所有的查询子类数据
@Override
//parentId: 父类 ID, 查询当前类别下的所有子类
//space : // 类别前面的空隔
public ArrayList<Sorts> getChildren(int parentId, String space, ArrayList<Sorts> arr){
if(arr == null){
//第一次查询
System.out.println(parentId);
arr = sortsDao.selectByParentId(parentId);
all = new ArrayList<>(); //第一次时, 初始化, 避免刷新调用重新添加信息
}
if(arr != null){
for(Sorts sorts : arr){
//根据级别不一样, 在前面加上相应的分隔符
int levels = sorts.getLevels();
if(levels == 1){
sorts.setSpace("");
}
else if(levels == 2){
space = " |---->";
sorts.setSpace(space);
}
else{
sorts.setSpace(space);
}
all.add(sorts); //将所有的信息都加到all里, 并增加一个space字段
parentId = sorts.getId();
ArrayList<Sorts> arr_child = sortsDao.selectByParentId(parentId);
if(arr_child != null){
getChildren(parentId," |" + space,arr_child);
}
}
}
return all;
}
@Override
//得到无限分类的select下拉列表
//pid : 父id
//selectName select的名字
//currenId : 被选择的id, 没有的话,传递0
public StringBuffer selectTrees(int pid, String selectName, int currentId) {
StringBuffer sBuffer = new StringBuffer();
ArrayList<Sorts> results = getChildren(pid,"",null);
if(results != null){
sBuffer.append("<select name='"+selectName+"'>\n");
sBuffer.append("<option value='0'>一级类别</option> \n");
for(Sorts sorts : results){
int id = sorts.getId();
if( id == currentId){
sBuffer.append("<option value='"+id+"' style='background:#E20A0A; color:#fff;' selected>"+
sorts.getSpace() + sorts.getSortName() + "</option> \n");
}
else{
sBuffer.append("<option value='"+id+"'>"+ sorts.getSpace() + sorts.getSortName() + "</option> \n");
}
}
sBuffer.append("</select>\n");
}
return sBuffer;
}
@Override
public String addSorts(Sorts sorts) {
//判断类名不能为空
if(sorts.getSortName().equals("")) {
return "<script>alert('类别名称不能为空');history.back();</script>";
}
//判断同一级下不能重复的名称
if(sortsDao.selectBySortNameAndParendId(sorts) != null){
return "<script>alert('父类下已存在相同类别!!!');history.back();</script>";
}
//设置level, sortpath 信息 begin
sorts.setLevels(1);
sorts.setSortPath("0,");
if(sorts.getParentId() != 0){
//最顶级时使用默认设置值, 否则根据父级来决定
Sorts getSorts = sortsDao.getOne(sorts.getParentId());
sorts.setLevels(getSorts.getLevels() + 1);
sorts.setSortPath(getSorts.getSortPath());
//暂时为父级sortPath, 当添加后, 再更新,将当前的id链接上
}
//将信息添加到数据库sorts
sortsDao.save(sorts); //sorts中会更新为新增加的id主键
//更新sortPath 到数据库
sorts.setSortPath(sorts.getSortPath() + sorts.getId() + ",");
sortsDao.save(sorts);
return "<script>alert('添加成功');location.href='/admin/sorts/list';</script>";
}
@Override
public String updateSorts(Sorts sorts) {
//判断类名不能为空
if(sorts.getSortName().equals("")) {
return "<script>alert('类别名称不能为空');history.back();</script>";
}
//根据id得到原来的信息
Sorts oldSorts = sortsDao.getOne(sorts.getId());
int oldPid = oldSorts.getParentId(); //原父id
String oldSortPath = oldSorts.getSortPath();
//判断类别名称是否重复
Sorts exitSorts = sortsDao.selectSortsByParentIdSortName(sorts);
if(exitSorts != null){
return "<script>alert('类别已经存在,请更换类别名称');history.back();</script>";
}
if(oldPid == sorts.getParentId()){
//父id不变, 则parentid, level都不需要修改
sorts.setSortPath(oldSorts.getSortPath());
sorts.setLevels(oldSorts.getLevels());
sortsDao.save(sorts);
}
else if(sorts.getParentId() == 0){
//移动到一级类别
sorts.setSortPath("0," + sorts.getId() + ",");
sorts.setLevels(1);
//更新当前类别信息
sortsDao.save(sorts);
//更新所有的修改类别的子类sortPath
Sorts sort1 = new Sorts();
sort1.setOldSortPath(oldSortPath);
sort1.setNewSortPath(sorts.getSortPath());
sort1.setId(sorts.getId());
sortsDao.updateAllChildSorts(sort1);
//更新所有子类的层级
sortsDao.updateAllChildSortsLevels(sort1);
}
else{
//判断是否移到到了子类另, 这样是不允许的, 中间会断层
//得到当前父类的path
Sorts parentSorts = sortsDao.getOne(sorts.getParentId());
String parentSortPath = parentSorts.getSortPath();
if(parentSortPath.indexOf(oldSortPath) >= 0){
return "<script>alert('类别不能选择为原父类的子类');history.back();</script>";
}
else{
//父类更新到上一级或者其它的类别下, 那么该类别下所有的子类都需要更新父级sortpath
//新的sortpath
String newSortPath = parentSortPath + sorts.getId() + ",";
int newLevel = parentSorts.getLevels() + 1;
sorts.setSortPath(newSortPath);
sorts.setLevels(newLevel);
sortsDao.save(sorts);
//更新所有的修改类别的子类
//更新所有的修改类别的子类sortPath
//更新所有的修改类别的子类sortPath
Sorts sort1 = new Sorts();
sort1.setOldSortPath(oldSortPath);
sort1.setNewSortPath(sorts.getSortPath());
sort1.setId(sorts.getId());
sortsDao.updateAllChildSorts(sort1);
//更新所有子类的层级
sortsDao.updateAllChildSortsLevels(sort1);
}
}
return "<script>alert('修改成功');location.href='/admin/sorts/list';</script>";
}
//删除所有的子类
@Override
public String deleteAllSortsById(Integer id) {
sortsDao.deleteAllSortsById(id);
return "<script>alert('删除成功');location.href='/admin/sorts/list';</script>";
}
}五. 控制器实现如下:
@Controller
public class SortsController {
@Autowired
@Qualifier("sortsService")
private SortsService sortsService;
@Autowired
private SortsRepository sortsDao;
@GetMapping(value = "/admin/sorts/add")
public String add(@RequestParam(defaultValue = "0") Integer parentId, Model model){
model.addAttribute("selectTrees",sortsService.selectTrees(0,"parentId",parentId));
return "admin/sorts/add";
}
@PostMapping(value = "/admin/sorts/addSave")
@ResponseBody
public String addSave(Sorts sorts){
return sortsService.addSorts(sorts);
}
@GetMapping(value = "/admin/sorts/list")
public String list(Model model){
ArrayList<Sorts> all = sortsService.getChildren(0,"",null);
model.addAttribute("all",all);
return "admin/sorts/list";
}
@GetMapping(value = "/admin/sorts/update")
public String update(@RequestParam(defaultValue = "0") Integer id,Model model){
Sorts sorts = sortsDao.getOne(id);
model.addAttribute("sorts",sorts);
model.addAttribute("selectTrees",sortsService.selectTrees(0,"parentId",sorts.getParentId()));
return "/admin/sorts/update";
}
@PostMapping(value = "/admin/sorts/updateSave")
@ResponseBody
public String updateSave(Sorts sorts){
return sortsService.updateSorts(sorts);
}
@GetMapping(value = "/admin/sorts/del")
@ResponseBody
public String del(@RequestParam(defaultValue = "0") Integer id){
return sortsService.deleteAllSortsById(id);
}
}六. 对应的视图文件如下:
添加视图:
<form action="/admin/sorts/addSave" method="post">
<li>
<label>父级类别:</label>
[(${selectTrees})]
</li>
<li>
<lable>类别名称: </lable>
<input type="text" name="sortName" />
</li>
<li>
<label>排序: </label>
<input type="number" name="orders" value="1" />
</li>
<li>
<input type="submit"/>
</li>
</form>修改视图:
<form action="/admin/sorts/updateSave" method="post" th:object="${sorts}">
<li>
<label>父级类别:</label>
[(${selectTrees})]
</li>
<li>
<lable>类别名称: </lable>
<input type="text" th:field="*{sortName}"/>
</li>
<li>
<label>排序: </label>
<input type="number" th:field="*{orders}"/>
</li>
<li>
<input type="hidden" th:field="*{id}">
<input type="submit"/>
</li>
</form>列表视图:
<table>
<tr>
<td colspan="4">
<a href="/admin/sorts/add">添加一级类别</a>
</td>
</tr>
<tr>
<td>ID</td>
<td>类别名称</td>
<td>排序</td>
<td>操作</td>
</tr>
<tr th:each="sorts : ${all}">
<td th:text="${sorts.id}">id</td>
<td th:text="${sorts.space}+${sorts.sortName}">类别名称</td>
<td th:text="${sorts.orders}">排序</td>
<td>
<a th:href="@{'/admin/sorts/add?parentId='+ ${sorts.id}}">添加子类</a>
<a th:href="@{'/admin/sorts/update?id='+ ${sorts.id}}">修改</a>
<a th:href="@{'/admin/sorts/del?id='+ ${sorts.id}}" onclick="return confirm('确认要删除吗');">删除</a>
</td>
</tr>
</table>源码下载:
