分类管理和标签管理的功能和页面都很相似,都是两个页面,一个新增页面,一个列表显示页面。
新增、编辑页面
列表显示页面
新增、编辑
新增和编辑都是在一个页面实现,可以通过是否有id,判断是进行新增操作还是修改操作。
前端核心代码
html代码
<div class="m-container-big m-padded-tn-big">
<div class="ui container">
<form action="#" method="POST" th:object="${type}" th:action="*{id}==null ? @{/admin/types} : @{/admin/types/{id}(id=*{id})}" class="ui form">
<input type="hidden" name="id" th:value="*{id}">
<div class="required field">
<div class="ui left labeled input">
<label class="ui teal basic label">名称</label>
<input type="text" name="name" placeholder="分类名称" th:value="*{name}">
</div>
</div>
<!-- 错误信息会显示在这里 -->
<div class="ui error message"></div>
<div class="ui negative message" th:if="${#fields.hasErrors('name')}" >
<i class="close icon"></i>
<div class="header">验证失败</div>
<p th:errors="*{name}">提交信息不符合规则</p>
</div>
<div class="ui right aligned container">
<button type="button" class="ui button" onclick="widows.history.go(-1)">返回</button>
<button class="ui teal submit button">提交</button>
</div>
</form>
</div>
</div>
th:action="*{id}==null ? @{/admin/types} : @{/admin/types/{id}(id=*{id})}"
这里用了三元运算符 如果id不为空则进行修改操作,id为空则进行编辑操作。
<input type="hidden" name="id" th:value="*{id}">
这里放了一个隐含域 ,从列表显示页面点击编辑会跳转到新增页面,同时将id传过来。根据id进行修改。
后面是错误信息提示,包括分类/标签不能为空,分类/标签已存在。非空判断在前端进行
js代码
$('.ui.form').form({
fields:{
title:{
identifier: 'name', //和表单里的name值一致
rules: [{
type: 'empty', //非空验证
prompt: '请输入分类名称',
}]
}
}
})
后端核心代码
service层实现类
@Transactional
@Override
public Type saveType(Type type) {
return typeRepository.save(type);
}
@Override
public Type getTypeByName(String name) {
return typeRepository.findByName(name);
}
@Transactional
@Override
public Type updateType(Long id, Type type) {
Type t= typeRepository.getById(id);
if(t==null){
throw new NotFoundException("不存在该类型");
}
BeanUtils.copyProperties(type,t);//将type复制到t
return typeRepository.save(t);
}
此处需要注意的是,涉及到增删改操作最好放在事务里面,添加@Transactional注解
controller层
@PostMapping("/types")
public String addtype(@Valid Type type, BindingResult bindingResult,
RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "admin/type-input";
}
Type type1=typeService.getTypeByName(type.getName());
if(type1!=null){
bindingResult.rejectValue("name","nameError","该分类已存在,不可重复添加");
}
Type t=typeService.saveType(type);
if(t==null){
attributes.addFlashAttribute("message","新增失败");
}else{
attributes.addFlashAttribute("message","新增成功");
}
return "redirect:/admin/types";
}
@PostMapping("/types/{id}")
public String edittype(@Valid Type type, BindingResult bindingResult,@PathVariable
Long id ,RedirectAttributes attributes){
Type type1=typeService.getTypeByName(type.getName());
if(type1!=null){
bindingResult.rejectValue("name","nameError","该分类已存在,不可重复添加");
}
if(bindingResult.hasErrors()){
return "admin/type-input";
}
Type t=typeService.updateType(id,type);
if(t==null){
attributes.addFlashAttribute("message","修改失败");
}else{
attributes.addFlashAttribute("message","修改成功");
}
return "redirect:/admin/types";
}
通过@Valid和@NotBlank注解在后端进行非空判断,这段代码写在Type实体类中。BindingResult用在实体类校验信息返回结果绑定,和@Valid一起使用,并且一定要写在@Valid之后。
@NotBlank(message = "分类名称不能为空")
private String name;
@PathVariable注解是用于拿到路径中的参数,这里可以获取到id值,然后根据id值进行修改操作。
新增/编辑大概主要就是这些。
列表显示
后端核心代码
service层实现类
@Transactional
@Override
public Page<Type> listType(Pageable pageable) {
return typeRepository.findAll(pageable);
}
返回一个page ,其中有分页总条数,总页数,当前页是否为第一页或最后一页等。
controller层
@GetMapping("/types")
public String types(@PageableDefault(size=5,sort={"id"} ,direction =
Sort.Direction.DESC)
Pageable pageable, Model model){
model.addAttribute("page",typeService.listType(pageable));
System.out.println(typeService.listType(pageable));
return "admin/types";
}
通过@PageableDefault注解可以初始化分页的默认条件,如每页几条数据,按照哪个字段排序,正序还是倒序。
前端核心代码
<div class="m-container m-padded-tn-big">
<div class="ui container">
<!-- 消息提示 -->
<div class="ui success message " th:unless="${#strings.isEmpty(message)}">
<i class="close icon"></i>
<div class="header">提示:</div>
<p th:text="${message}"></p>
</div>
<table class="ui celled table">
<thead>
<tr>
<th></th>
<th>分类名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="type,iterStat : ${page.content}">
<!-- iterStat 拿到分页数据的索引 -->
<td th:text="${iterStat.count}">1</td>
<td th:text="${type.name}"></td>
<td>
<a href="#" th:href="@{/admin/types/{id}/input(id=${type.id})}" class="ui mini positive basic button">编辑</a>
<a href="#" th:href="@{/admin/types/{id}/delete(id=${type.id})}" class="ui mini negative basic button">删除</a>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="6" >
<div class="ui mini pagination menu" th:if="${page.totalPages>1}">
<a th:href="@{/admin/types(page=${page.number}-1)}" class=" item" th:unless="${page.first}">上一页</a>
<a th:href="@{/admin/types(page=${page.number}+1)}" class="mini item" th:unless="${page.last}" >下一页</a>
</div>
<a href="#" th:href="@{/admin/types/input}" class="ui mini right floated teal basic button">新增</a>
</th>
</tr>
</tfoot>
</table>
</div>
</div>
消息提示部分是显示操作是否成功,通过js代码控制。
//消息提示关闭初始化
$('.message .close').on('click',function(){
$(this).closest('.message')
.transition('fade');
});
通过 th:each 循环分页内容拿到每一条数据和索引(iterStat.count),然后显示在表格中。底部的分页条,如果总页数只有一页就不显示,当当前页是第一页是不显示上一页的按钮,当当前页是最后一页时不显示下一页的按钮。分别通过 th:if="${page.totalPages>1}",th:unless="${page.first}",th:unless="${page.last}"来判断。
最后就是删除了,直接根据id进行删除操作就行了。分类/标签管理就差不多了。
冲啊!!!
SpringBoot开发一个小而美的个人博客(一) 前端页面(一)_舒克、舒克的博客-CSDN博客_springboot开发一个页面
SpringBoot开发一个小而美的个人博客(二) 前端页面(二)_舒克、舒克的博客-CSDN博客
SpringBoot开发一个小而美的个人博客(三) 框架搭建_舒克、舒克的博客-CSDN博客_springboot开发个人博客