分类相关功能设计

master
barney 2 years ago
parent 8227dcd66b
commit a90a200bcc
  1. 1
      README.md
  2. 54
      src/main/java/cc/bnblogs/common/Result.java
  3. 4
      src/main/java/cc/bnblogs/controller/AdminController.java
  4. 52
      src/main/java/cc/bnblogs/controller/CategoryController.java
  5. 25
      src/main/java/cc/bnblogs/enums/ResultEnum.java
  6. 11
      src/main/java/cc/bnblogs/mapper/CategoryMapper.java
  7. 37
      src/main/java/cc/bnblogs/pojo/Category.java
  8. 64
      src/main/java/cc/bnblogs/service/CategoryService.java
  9. 74
      src/main/resources/static/plugin/jquery/jquery.form.js
  10. 2
      src/main/resources/static/plugin/layer/layer.js
  11. 2
      src/main/resources/static/plugin/layer/mobile/layer.js
  12. 1
      src/main/resources/static/plugin/layer/mobile/need/layer.css
  13. BIN
      src/main/resources/static/plugin/layer/theme/default/icon-ext.png
  14. BIN
      src/main/resources/static/plugin/layer/theme/default/icon.png
  15. 1
      src/main/resources/static/plugin/layer/theme/default/layer.css
  16. BIN
      src/main/resources/static/plugin/layer/theme/default/loading-0.gif
  17. BIN
      src/main/resources/static/plugin/layer/theme/default/loading-1.gif
  18. BIN
      src/main/resources/static/plugin/layer/theme/default/loading-2.gif
  19. 117
      src/main/resources/templates/admin/category.html
  20. 9
      src/main/resources/templates/admin/common.html
  21. 54
      src/test/java/cc/bnblogs/test/CategoryTest.java

@ -0,0 +1 @@
### 基于Springboot和Thymeleaf的博客项目

@ -0,0 +1,54 @@
package cc.bnblogs.common;
import cc.bnblogs.enums.ResultEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
@Data
@AllArgsConstructor
public class Result<T>{
// 状态码
private Integer code;
// 返回的信息
private String message;
// 返回的具体数据
private T data;
/**
*
* @param resultEnum
*/
private Result(ResultEnum resultEnum) {
this.code = resultEnum.getCode();
this.message = resultEnum.getMessage();
}
private Result(ResultEnum resultEnum, T data) {
this.code = resultEnum.getCode();
this.message = resultEnum.getMessage();
this.data = data;
}
public static <T> Result<T> success() {
return new Result<>(ResultEnum.RESULT_SUCCESS);
}
public static <T> Result<T> success(T data) {
return new Result<>(ResultEnum.RESULT_SUCCESS,data);
}
public static <T> Result<T> error() {
return new Result<>(ResultEnum.RESULT_ERROR);
}
public static <T> Result<T> error(ResultEnum resultEnum) {
return new Result<>(resultEnum);
}
public static <T> Result<T> error(Integer code, String message) {
return new Result<>(code,message,null);
}
}

@ -15,4 +15,8 @@ public class AdminController {
public String getIndex() {
return "admin/index";
}
@GetMapping("/category.html")
public String getCategory() {
return "admin/category";
}
}

@ -0,0 +1,52 @@
package cc.bnblogs.controller;
import cc.bnblogs.common.Result;
import cc.bnblogs.enums.ResultEnum;
import cc.bnblogs.pojo.Category;
import cc.bnblogs.service.CategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Objects;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
@RestController
@RequestMapping("/admin/category")
public class CategoryController {
private final CategoryService categoryService;
public CategoryController(CategoryService categoryService) {
this.categoryService = categoryService;
}
/**
* 请求所有分类的接口
* @return 返回所有分类
*/
@GetMapping("/")
public Result<List<Category>> list() {
return Result.success(categoryService.list());
}
/**
* 请求分类详情的接口
* @param id 分类id
* @return 返回分类的详情
*/
@GetMapping("/{id}")
public Result<Category> detail(@PathVariable Integer id) {
Category category = categoryService.detail(id);
if (Objects.isNull(category)) {
return Result.error(ResultEnum.RESULT_NOT_FOUND);
} else {
return Result.success(category);
}
}
}

@ -0,0 +1,25 @@
package cc.bnblogs.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
@Getter
@AllArgsConstructor
public enum ResultEnum {
/**
* 操作结果的枚举常量
*/
RESULT_SUCCESS(200,"请求成功"),
RESULT_NOT_FOUND(404,"数据不存在"),
RESULT_ERROR(500,"系统错误");
private final Integer code;
private final String message;
}

@ -0,0 +1,11 @@
package cc.bnblogs.mapper;
import cc.bnblogs.pojo.Category;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
public interface CategoryMapper extends JpaRepository<Category,Integer> {
}

@ -0,0 +1,37 @@
package cc.bnblogs.pojo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name="blog_category")
public class Category {
/**
* 分类id(主键)
* 主键自增
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 分类名(唯一)
*/
@Column(unique = true)
private String name;
/**
* 分类介绍
*/
private String summary;
}

@ -0,0 +1,64 @@
package cc.bnblogs.service;
import cc.bnblogs.mapper.CategoryMapper;
import cc.bnblogs.pojo.Category;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
@Service
public class CategoryService {
private final CategoryMapper categoryMapper;
public CategoryService(CategoryMapper categoryMapper) {
this.categoryMapper = categoryMapper;
}
/**
* 获取所有分类
* @return 分类列表
*/
public List<Category> list() {
return categoryMapper.findAll();
}
/**
* 获取分类总数
* @return 分类总数
*/
public long count() {
return categoryMapper.count();
}
/**
* 根据id查询分类对象
* @param id 分类id
* @return id对应的分类对象
*/
public Category detail(Integer id) {
return categoryMapper.findById(id).orElse(null);
}
/**
* 保存分类
* @param category 带保存的分类对象
*/
public void save(Category category) {
categoryMapper.save(category);
}
/**
* 根据id删除分类对象
* @param id 待删除分类的id
*/
public void delete(Integer id) {
categoryMapper.deleteById(id);
}
}

@ -0,0 +1,74 @@
(function ($) {
$.fn.extend({
initForm: function (options) {
//默认参数
var defaults = {
jsonValue: options,
isDebug: false //是否需要调试,这个用于开发阶段,发布阶段请将设置为false,默认为false,true将会把name value打印出来
}
//设置参数
var setting = defaults;
var form = this;
jsonValue = setting.jsonValue;
//如果传入的json字符串,将转为json对象
if ($.type(setting.jsonValue) === "string") {
jsonValue = $.parseJSON(jsonValue);
}
//如果传入的json对象为空,则不做任何操作
if (!$.isEmptyObject(jsonValue)) {
var debugInfo = "";
$.each(jsonValue, function (key, value) {
//是否开启调试,开启将会把name value打印出来
if (setting.isDebug) {
alert("name:" + key + "; value:" + value);
debugInfo += "name:" + key + "; value:" + value + " || ";
}
var formField = form.find("[name='" + key + "']");
if ($.type(formField[0]) === "undefined") {
if (setting.isDebug) {
alert("can not find name:[" + key + "] in form!!!"); //没找到指定name的表单
}
} else {
var fieldTagName = formField[0].tagName.toLowerCase();
if (fieldTagName == "input") {
if (formField.attr("type") == "radio") {
$("input:radio[name='" + key + "'][value='" + value + "']").attr("checked", "checked");
} else {
formField.val(value);
}
} else if (fieldTagName == "select") {
//do something special
formField.val(value);
} else if (fieldTagName == "textarea") {
//do something special
formField.val(value);
} else {
formField.val(value);
}
}
})
if (setting.isDebug) {
alert(debugInfo);
}
}
return form; //返回对象,提供链式操作
},
serializeJson: function () {
const serializeObj = {};
const 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;
}
});
})(jQuery)

File diff suppressed because one or more lines are too long

@ -0,0 +1,2 @@
/*! layer mobile-v2.0.0 Web 通用弹出层组件 MIT License */
;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'<h3 style="'+(e?n.title[1]:"")+'">'+(e?n.title[0]:n.title)+"</h3>":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type="1">'+n.btn[0]+"</span>",2===t&&(e='<span no type="0">'+n.btn[1]+"</span>"+e),'<div class="layui-m-layerbtn">'+e+"</div>"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='<i></i><i class="layui-m-layerload"></i><i></i><p>'+(n.content||"")+"</p>"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"<div "+("string"==typeof n.shade?'style="'+n.shade+'"':"")+' class="layui-m-layershade"></div>':"")+'<div class="layui-m-layermain" '+(n.fixed?"":'style="position:static;"')+'><div class="layui-m-layersection"><div class="layui-m-layerchild '+(n.skin?"layui-m-layer-"+n.skin+" ":"")+(n.className?n.className:"")+" "+(n.anim?"layui-m-anim-"+n.anim:"")+'" '+(n.style?'style="'+n.style+'"':"")+">"+l+'<div class="layui-m-layercont">'+n.content+"</div>"+c+"</div></div></div>",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i]("layui-m-layershade")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:"2.0",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a("#"+o[0]+e)[0];n&&(n.innerHTML="",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],"function"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute("index"))}},"function"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf("/")+1);n.getAttribute("merge")||document.head.appendChild(function(){var e=t.createElement("link");return e.href=a+"need/layer.css?2.0",e.type="text/css",e.rel="styleSheet",e.id="layermcss",e}())}()}(window);

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head th:replace="admin/common::header(~{::title},~{},~{})">
<title>分类管理</title>
</head>
<body>
<th:block th:include="admin/common::nav('category')"></th:block>
<div class="container lw-main lw-banner">
<div class="btn-group" role="group" style="margin-bottom: 20px" aria-label="...">
<button type="button" class="btn btn-default"><i class="fa fa-plus"></i> 新增</button>
</div>
<table id="data-table"></table>
</div>
<!-- 编辑窗口 -->
<div class="modal fade" id="save-window" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form id="data-form">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="window-title">Modal Title</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label>标题</label>
<input type="text" name="name" class="form-control" placeholder="请输入标题...">
</div>
<div class="form-group">
<label>描述信息</label>
<textarea class="form-control" name="summary" placeholder="请输入描述信息..."></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
</div>
<th:block th:include="admin/common::footer"></th:block>
<script>
$(function () {
// $("#save-window").modal("show")
$('#data-table').bootstrapTable({
url: "/admin/category/",
columns: [
{
title: "序号",
width: 50,
align: 'center',
// 生成自增的序号
formatter: function (value, row, index) {
return index + 1
}
}
,
{
title: "标题",
field: "name",
},
{
title: "描述",
field: "summary",
},
{
field: "id",
title: '操作',
align: "center",
width: 180,
formatter: function (value) {
return `<button type="button" data-id="${value}" class="btn btn-info btn-sm category-edit-btn"><i class="fa fa-edit"></i> 编辑</button>
<button type="button" data-id="${value}" class="btn btn-danger btn-sm category-delete-btn"><i class="fa fa-trash"></i> 删除</button>`
}
}
],
responseHandler: function (res) {
return res.data
}
})
$("#data-table").on("click",".category-edit-btn",function () {
let id = $(this).data("id")
$.ajax({
url: "/admin/category/" + id,
method: 'GET',
dataType: 'json',
success: res => {
if (res.code === 200) {
$("#window-title").text('编辑分类')
$("#data-form").initForm(res.data)
$('#save-window').modal('show')
}
else {
layer.msg(res.message, {icon: 2})
}
}
})
console.log(id);
})
$("#data-table").on("click",".category-delete-btn",function () {
let id = $(this).data("id")
console.log(id);
})
})
</script>
</body>
</html>

@ -35,9 +35,11 @@
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li th:class="${active eq 'index'} ? 'active': ''"><a href="#">控制台 <span class="sr-only">(current)</span></a></li>
<li th:class="${active eq 'index'} ? 'active': ''">
<a th:href="@{/admin/}">控制台<span class="sr-only">(current)</span></a>
</li>
<li th:class="${active eq 'article'} ? 'active': ''"><a href="#">文章管理</a></li>
<li th:class="${active eq 'category'} ? 'active': ''"><a href="#">分类管理</a></li>
<li th:class="${active eq 'category'} ? 'active': ''"><a th:href="@{/admin/category.html}">分类管理</a></li>
<li th:class="${active eq 'views'} ? 'active': ''"><a href="#">轮播图管理</a></li>
<li><a href="#">页面管理</a></li>
<li><a href="#">友链管理</a></li>
@ -66,10 +68,13 @@
</div>
</footer>
<script src="/static/plugin/jquery/jquery-3.5.1.min.js"></script>
<script src="/static/plugin/jquery/jquery.form.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="/static/plugin/bootstrap/js/bootstrap.min.js"></script>
<script src="/static/plugin/bootstrap-table/bootstrap-table.min.js"></script>
<script src="/static/plugin/bootstrap-table/bootstrap-table-zh-CN.js"></script>
<script src="/static/plugin/layer/layer.js"></script>
</th:block>

@ -0,0 +1,54 @@
package cc.bnblogs.test;
import cc.bnblogs.Application;
import cc.bnblogs.mapper.CategoryMapper;
import cc.bnblogs.pojo.Category;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/16
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CategoryTest {
@Autowired
private CategoryMapper categoryMapper;
@Test
public void newEntity() {
Category c1 = Category.builder().
id(1).name("xxx").summary("id").build();
System.out.println(c1);
}
@Test
public void testUpdate() {
Category category = categoryMapper.findById(2).orElse(null);
System.out.println(category);
assert category != null;
category.setName("新分类");
categoryMapper.save(category);
System.out.println(categoryMapper.findById(2));
}
@Test
public void testAdd() {
// 如果id不为null则是更新操作,否则是插入操作
for (int i = 2; i <= 10; i++) {
categoryMapper.save(Category.builder().
id(i).name("测试分类" + i).summary("测试分类" + i + "的描述...").build());
}
}
@Test
public void testFind() {
System.out.println(categoryMapper.findAll());
}
}
Loading…
Cancel
Save