GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

编程开发记录之若依脚手架 --- 代码生成

所谓代码生成就是使用若依后台管理系统的代码生成功能,依据已有数据库自动生成前后端的增删改查代码。

流程简述:

1.创建数据库与表,并注释表和字段  (注意数据库中的命名要规范,比如学生姓名 stu_name),例如我手动创建了如下学生表

 2.配置主页菜单,配置代码生成的参数,点击代码生成

配置主页菜单示例如下

一级目录配置 

二级目录配置

 

 

 

配置代码生成的参数示例如下

 

 

 

 


3.创建模块,修改主pom、admin的pom和自己的pom,移动生成的代码到创建的模块目录下,执行sql

例子

因为上面的例子没有创建模块,所以不需要配置pom文件。

按照包路径移动到正确的目录下,我的是com.ruoyi.biz,因此应该代码放置到biz目录下

使用heidisql工具执行压缩包里的sql使其前端展示生效

4.一定要重启idea,否者不生效

 

生成代码详解:

当我们点击预览它会生成下面的文件,我们一个一个解释

 

domain.java,这是java实体的代码,属于java基础内容,不过多介绍。这里的文章java实体对应的是数据库里的文章表字段
package com.ruoyi.biz.article.domain;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.framework.web.domain.BaseEntity;

/**
 * 文章管理对象 biz_article
 * 
 * @author gk
 * @date 2023-05-21
 */
public class BizArticle extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 文章ID */
    private Integer articaleId;

    /** 文章标题 */
    @Excel(name = "文章标题")
    private String articleTitle;

    /** 文章内容 */
    @Excel(name = "文章内容")
    private String articleContent;

    /** 文章封面 */
    @Excel(name = "文章封面")
    private String articleImg;

    /** 部门ID */
    @Excel(name = "部门ID")
    private Long deptId;

    /** 文章类别 */
    @Excel(name = "文章类别")
    private Integer categoryId;

    /** 文章状态 */
    @Excel(name = "文章状态")
    private String articleStatus;

    /** 审核人员ID */
    @Excel(name = "审核人员ID")
    private Integer articleAuditUserid;

    /** 审核人员用户名 */
    @Excel(name = "审核人员用户名")
    private String articleAuditUsername;

    /** 排序 */
    @Excel(name = "排序")
    private Long sort;

    public void setArticaleId(Integer articaleId)
    {
        this.articaleId = articaleId;
    }

    public Integer getArticaleId()
    {
        return articaleId;
    }
    public void setArticleTitle(String articleTitle)
    {
        this.articleTitle = articleTitle;
    }

    public String getArticleTitle()
    {
        return articleTitle;
    }
    public void setArticleContent(String articleContent)
    {
        this.articleContent = articleContent;
    }

    public String getArticleContent()
    {
        return articleContent;
    }
    public void setArticleImg(String articleImg)
    {
        this.articleImg = articleImg;
    }

    public String getArticleImg()
    {
        return articleImg;
    }
    public void setDeptId(Long deptId)
    {
        this.deptId = deptId;
    }

    public Long getDeptId()
    {
        return deptId;
    }
    public void setCategoryId(Integer categoryId)
    {
        this.categoryId = categoryId;
    }

    public Integer getCategoryId()
    {
        return categoryId;
    }
    public void setArticleStatus(String articleStatus)
    {
        this.articleStatus = articleStatus;
    }

    public String getArticleStatus()
    {
        return articleStatus;
    }
    public void setArticleAuditUserid(Integer articleAuditUserid)
    {
        this.articleAuditUserid = articleAuditUserid;
    }

    public Integer getArticleAuditUserid()
    {
        return articleAuditUserid;
    }
    public void setArticleAuditUsername(String articleAuditUsername)
    {
        this.articleAuditUsername = articleAuditUsername;
    }

    public String getArticleAuditUsername()
    {
        return articleAuditUsername;
    }
    public void setSort(Long sort)
    {
        this.sort = sort;
    }

    public Long getSort()
    {
        return sort;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
            .append("articaleId", getArticaleId())
            .append("articleTitle", getArticleTitle())
            .append("articleContent", getArticleContent())
            .append("articleImg", getArticleImg())
            .append("deptId", getDeptId())
            .append("categoryId", getCategoryId())
            .append("articleStatus", getArticleStatus())
            .append("articleAuditUserid", getArticleAuditUserid())
            .append("articleAuditUsername", getArticleAuditUsername())
            .append("createBy", getCreateBy())
            .append("createTime", getCreateTime())
            .append("updateBy", getUpdateBy())
            .append("sort", getSort())
            .append("updateTime", getUpdateTime())
            .append("remark", getRemark())
            .toString();
    }
}

 

 

mapper.java  用于有映射到xml文件的sql语句中的id,表示具有的增删改查功能,具体操作有xml文件定义
package com.ruoyi.biz.article.mapper;

import java.util.List;
import com.ruoyi.biz.article.domain.BizArticle;

/**
 * 文章管理Mapper接口
 * 
 * @author gk
 * @date 2023-05-21
 */
public interface BizArticleMapper 
{
    /**
     * ID查询文章,用于在编辑文章时先查询具体的文章*/
    public BizArticle selectBizArticleById(Integer articaleId);

    /**
     * 对象查文章列表,用于前端的搜索*/
    public List<BizArticle> selectBizArticleList(BizArticle bizArticle);

    /**
     * 新增文章,返回增加成功数*/
    public int insertBizArticle(BizArticle bizArticle);

    /**
     * 修改文章*/
    public int updateBizArticle(BizArticle bizArticle);

    /**
     * id删文章,用于一个条目删除*/
    public int deleteBizArticleById(Integer articaleId);

    /**
     * 批量删文章,用于多个条目删除*/
    public int deleteBizArticleByIds(String[] articaleIds);
}

 

 

 

service.java ,函数命名可以和数据库服务一致,用于包含具体的业务逻辑,并调用数据库服务,比如我不想给前端提供删除服务,这里删除即可
package com.ruoyi.biz.article.service;

import java.util.List;
import com.ruoyi.biz.article.domain.BizArticle;

/**
 * 文章管理Service接口
 * 
 * @author gk
 * @date 2023-05-21
 */
public interface IBizArticleService 
{
    /**
     * 查询文章管理
     * 
     * @param articaleId 文章管理ID
     * @return 文章管理
     */
    public BizArticle selectBizArticleById(Integer articaleId);

    /**
     * 查询文章管理列表
     * 
     * @param bizArticle 文章管理
     * @return 文章管理集合
     */
    public List<BizArticle> selectBizArticleList(BizArticle bizArticle);

    /**
     * 新增文章管理
     * 
     * @param bizArticle 文章管理
     * @return 结果
     */
    public int insertBizArticle(BizArticle bizArticle);

    /**
     * 修改文章管理
     * 
     * @param bizArticle 文章管理
     * @return 结果
     */
    public int updateBizArticle(BizArticle bizArticle);

    /**
     * 批量删除文章管理
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    public int deleteBizArticleByIds(String ids);

    /**
     * 删除文章管理信息
     * 
     * @param articaleId 文章管理ID
     * @return 结果
     */
    public int deleteBizArticleById(Integer articaleId);
}

 

 

 

 

 

serviceImpl.java ,该类是上一个服务接口的实现类

package com.ruoyi.biz.article.service.impl;

import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.biz.article.mapper.BizArticleMapper;
import com.ruoyi.biz.article.domain.BizArticle;
import com.ruoyi.biz.article.service.IBizArticleService;
import com.ruoyi.common.utils.text.Convert;

/**
 * 文章管理Service业务层处理
 * 
 * @author gk
 * @date 2023-05-21
 */
@Service
public class BizArticleServiceImpl implements IBizArticleService 
{
    @Autowired
    private BizArticleMapper bizArticleMapper;

    /**
     * 查询文章管理
     * 
     * @param articaleId 文章管理ID
     * @return 文章管理
     */
    @Override
    public BizArticle selectBizArticleById(Integer articaleId)
    {
        return bizArticleMapper.selectBizArticleById(articaleId);
    }

    /**
     * 查询文章管理列表
     * 
     * @param bizArticle 文章管理
     * @return 文章管理
     */
    @Override
    public List<BizArticle> selectBizArticleList(BizArticle bizArticle)
    {
        return bizArticleMapper.selectBizArticleList(bizArticle);
    }

    /**
     * 新增文章管理
     * 
     * @param bizArticle 文章管理
     * @return 结果
     */
    @Override
    public int insertBizArticle(BizArticle bizArticle)
    {
        bizArticle.setCreateTime(DateUtils.getNowDate());
        return bizArticleMapper.insertBizArticle(bizArticle);
    }

    /**
     * 修改文章管理
     * 
     * @param bizArticle 文章管理
     * @return 结果
     */
    @Override
    public int updateBizArticle(BizArticle bizArticle)
    {
        bizArticle.setUpdateTime(DateUtils.getNowDate());
        return bizArticleMapper.updateBizArticle(bizArticle);
    }

    /**
     * 删除文章
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteBizArticleByIds(String ids)
    {
        return bizArticleMapper.deleteBizArticleByIds(Convert.toStrArray(ids));
    }

    /**
     * id删除文章
     * 
     * @param articaleId 文章管理ID
     * @return 结果
     */
    @Override
    public int deleteBizArticleById(Integer articaleId)
    {
        return bizArticleMapper.deleteBizArticleById(articaleId);
    }
}

 

 

 

上面代码稍微有点java基础的都能看懂,下面几个文件就相对复杂了。

controller.java 用于定义url接口同时调用后台服务对象
package com.ruoyi.biz.article.controller;

import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions; //配置访问权限类
import org.springframework.beans.factory.annotation.Autowired; //自动new类
import org.springframework.stereotype.Controller; //定义接口类
import org.springframework.ui.ModelMap;  //用于临时保存数据类
import org.springframework.web.bind.annotation.GetMapping; //用于收get请求类
import org.springframework.web.bind.annotation.PathVariable; //用于获取url路径类
import org.springframework.web.bind.annotation.PostMapping; //用于收post请求类
import org.springframework.web.bind.annotation.RequestMapping; //用于收任何包类
import org.springframework.web.bind.annotation.ResponseBody; //用于返回字符串
import com.ruoyi.framework.aspectj.lang.annotation.Log; //用于生成控制台日志
import com.ruoyi.framework.aspectj.lang.enums.BusinessType; //日志要是的类型常量
import com.ruoyi.biz.article.domain.BizArticle;  
import com.ruoyi.biz.article.service.IBizArticleService;
import com.ruoyi.framework.web.controller.BaseController; 
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil; //excle导出工具
import com.ruoyi.framework.web.page.TableDataInfo; //分表操作

/**
 * 文章管理Controller
 * 
 * @author gk
 * @date 2023-05-21
 */
@Controller //注释它是一个控制器类
@RequestMapping("/biz/article") //收到的url是 /biz/article就访问这个类
public class BizArticleController extends BaseController  //继承了基本控制器
{
    private String prefix = "biz/article"; //用于定义url前缀

    @Autowired  //自动new
    private IBizArticleService bizArticleService;

  //返回文章页 @RequiresPermissions(
"biz:article:view") //注释只有view权限的角色才能访问该接口 @GetMapping() // 类上的接口定义+本接口定义就是url相对路径,即就是get /biz/article/ public String article() { return prefix + "/article"; //它会自动在url相对路径加上/article,及就是 /biz/article/article字符串返回,模板引擎会接收到url找到对应的前端网页article.html } /** * 查询文章列表 */ @RequiresPermissions("biz:article:list") @PostMapping("/list") // post /biz/article/list ,提交的数据保存到下面的函数的article参数里,这里post参数要与bizarticle对象的属性名称对应 @ResponseBody //返回字符串 public TableDataInfo list(BizArticle bizArticle) { startPage(); //初始化分页处理 List<BizArticle> list = bizArticleService.selectBizArticleList(bizArticle); //查询出文章列表 return getDataTable(list); //依据列表开始分页 } /** * 导出文章列表 */ @RequiresPermissions("biz:article:export") @Log(title = "文章管理", businessType = BusinessType.EXPORT) @PostMapping("/export") @ResponseBody public AjaxResult export(BizArticle bizArticle) { List<BizArticle> list = bizArticleService.selectBizArticleList(bizArticle); ExcelUtil<BizArticle> util = new ExcelUtil<BizArticle>(BizArticle.class); return util.exportExcel(list, "article"); } /** * 返回新增页 */ @GetMapping("/add") public String add() { return prefix + "/add"; } /** * 保存新增 */ @RequiresPermissions("biz:article:add") @Log(title = "文章管理", businessType = BusinessType.INSERT) @PostMapping("/add") @ResponseBody public AjaxResult addSave(BizArticle bizArticle) { return toAjax(bizArticleService.insertBizArticle(bizArticle)); //这里使用了toajax封装了一下,返回状态码和新增数 } /** * 返回修改页 */ @GetMapping("/edit/{articaleId}") public String edit(@PathVariable("articaleId") Integer articaleId, ModelMap mmap) //这里的@pathvariable将 参数articaleId=路径里的articleId,modelmap的作用是向返回的页面传递数据 { BizArticle bizArticle = bizArticleService.selectBizArticleById(articaleId); //id查文章 mmap.put("bizArticle", bizArticle); //保存文章输送到前端页面,这是因为修改一个文章你得先有文章 return prefix + "/edit"; //返回页面 } /** * 保存修改 */ @RequiresPermissions("biz:article:edit") @Log(title = "文章管理", businessType = BusinessType.UPDATE) @PostMapping("/edit") //接收跟新文章 @ResponseBody public AjaxResult editSave(BizArticle bizArticle) { return toAjax(bizArticleService.updateBizArticle(bizArticle)); } /** * 删除文章 */ @RequiresPermissions("biz:article:remove") @Log(title = "文章管理", businessType = BusinessType.DELETE) @PostMapping( "/remove") @ResponseBody public AjaxResult remove(String ids) { return toAjax(bizArticleService.deleteBizArticleByIds(ids)); } }

 

 

mapper.xml 这是数据库sql语句定义文件,给mapper.java使用

<!-- mybatis将原本静态的sql变得动态起来,具备了编程语言的结构 -->
<?xml version="1.0" encoding="UTF-8" ?><!-- XML声明 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- DTD -->
<mapper namespace="com.ruoyi.biz.article.mapper.BizArticleMapper"> <!-- 指定使用的BizArticleMapper类 -->

<resultMap type="BizArticle" id="BizArticleResult"><!-- 这里映射sql查询结果到java文章实体 -->
<result property="articaleId" column="articale_id" />
<result property="articleTitle" column="article_title" />
<result property="articleContent" column="article_content" />
<result property="articleImg" column="article_img" />
<result property="deptId" column="dept_id" />
<result property="categoryId" column="category_id" />
<result property="articleStatus" column="article_status" />
<result property="articleAuditUserid" column="article_audit_userId" />
<result property="articleAuditUsername" column="article_audit_userName" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="sort" column="sort" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>

<sql id="selectBizArticleVo">
select articale_id, article_title, article_content, article_img, dept_id, category_id, article_status, article_audit_userId, article_audit_userName, create_by, create_time, update_by, sort, update_time, remark from biz_article
</sql>

<select id="selectBizArticleList" parameterType="BizArticle" resultMap="BizArticleResult">
<include refid="selectBizArticleVo"/>
<where> <!--前端传入文章属性是什么就查询什么-->
<if test="articleTitle != null and articleTitle != ''"> and article_title = #{articleTitle}</if>
<if test="articleContent != null and articleContent != ''"> and article_content = #{articleContent}</if>
<if test="articleImg != null and articleImg != ''"> and article_img = #{articleImg}</if>
<if test="deptId != null "> and dept_id = #{deptId}</if>
<if test="categoryId != null "> and category_id = #{categoryId}</if>
<if test="articleStatus != null and articleStatus != ''"> and article_status = #{articleStatus}</if>
<if test="articleAuditUserid != null "> and article_audit_userId = #{articleAuditUserid}</if>
<if test="articleAuditUsername != null and articleAuditUsername != ''"> and article_audit_userName like concat('%', #{articleAuditUsername}, '%')</if> <!--
 like  表示模糊匹配。
 concat()  函数用于将多个字符串拼接在一起。
 %  表示 0 个或多个字符,相当于通配符。
 #{articleAuditUsername}  是一个占位符,表示需要替换为具体的值。
最后生成的 SQL 语句可能类似于这样:

 
article_audit_userName like '%关键词%'
 

其中  关键词  是具体的搜索关键词,通过模糊匹配的方式查找符合条件的数据-->
<if test="sort != null "> and sort = #{sort}</if>
</where>
</select>

<select id="selectBizArticleById" parameterType="Integer" resultMap="BizArticleResult">
<include refid="selectBizArticleVo"/> <!-- 引入公共的sql语句-->
where articale_id = #{articaleId}
</select>

<insert id="insertBizArticle" parameterType="BizArticle" useGeneratedKeys="true" keyProperty="articaleId"> <!-- articaleId设置主键-->
insert into biz_article
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="articleTitle != null and articleTitle != ''">article_title,</if>
<if test="articleContent != null and articleContent != ''">article_content,</if>
<if test="articleImg != null">article_img,</if>
<if test="deptId != null">dept_id,</if>
<if test="categoryId != null">category_id,</if>
<if test="articleStatus != null and articleStatus != ''">article_status,</if>
<if test="articleAuditUserid != null">article_audit_userId,</if>
<if test="articleAuditUsername != null">article_audit_userName,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="sort != null">sort,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="articleTitle != null and articleTitle != ''">#{articleTitle},</if>
<if test="articleContent != null and articleContent != ''">#{articleContent},</if>
<if test="articleImg != null">#{articleImg},</if>
<if test="deptId != null">#{deptId},</if>
<if test="categoryId != null">#{categoryId},</if>
<if test="articleStatus != null and articleStatus != ''">#{articleStatus},</if>
<if test="articleAuditUserid != null">#{articleAuditUserid},</if>
<if test="articleAuditUsername != null">#{articleAuditUsername},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="sort != null">#{sort},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
</trim>
</insert>

<update id="updateBizArticle" parameterType="BizArticle">
update biz_article
<trim prefix="SET" suffixOverrides=",">
<if test="articleTitle != null and articleTitle != ''">article_title = #{articleTitle},</if>
<if test="articleContent != null and articleContent != ''">article_content = #{articleContent},</if>
<if test="articleImg != null">article_img = #{articleImg},</if>
<if test="deptId != null">dept_id = #{deptId},</if>
<if test="categoryId != null">category_id = #{categoryId},</if>
<if test="articleStatus != null and articleStatus != ''">article_status = #{articleStatus},</if>
<if test="articleAuditUserid != null">article_audit_userId = #{articleAuditUserid},</if>
<if test="articleAuditUsername != null">article_audit_userName = #{articleAuditUsername},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="sort != null">sort = #{sort},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
</trim>
where articale_id = #{articaleId}
</update>

<delete id="deleteBizArticleById" parameterType="Integer">
delete from biz_article where articale_id = #{articaleId}
</delete>

<delete id="deleteBizArticleByIds" parameterType="String"> <!-- 传入字符串ids -->
delete from biz_article where articale_id in
<foreach item="articaleId" collection="array" open="(" separator="," close=")"><!-- 字符串数组遍历取出来到articleid变量,最终的代码是(1,2,3...) -->
#{articaleId}
</foreach>
</delete>

</mapper>

 

 

list.html 前端文章子页面

list.html
<!-- -->

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<th:block th:include="include :: header('文章管理列表')" /> <!-- 使用th模板引擎引入头html文件-->
</head>
<body class="gray-bg">
<div class="container-div">
<div class="row">
<!-- 搜索框 -->
<div class="col-sm-12 search-collapse">
<form id="formId">
<div class="select-list">
<ul>
<li>
<label>文章标题:</label>
<input type="text" name="articleTitle"/>
</li>
<li>
<label>部门ID:</label>
<input type="text" name="deptId"/>
</li>
<li>
<label>文章类别:</label>
<!--这段代码用于在 HTML 页面中生成一个下拉选择框,以供用户选择文章类型。其中:
-->
<select name="categoryId" th:with="type=${@dict.getType('biz_article_type')}"><!-- name="categoryId"  表示该下拉选择框的名称为  categoryId ,当用户提交表单时,选择的值会作为参数的值传递到服务器端。
这一行代码是 Thymeleaf 的语法,用于将  @dict.getType('biz_article_type')  的返回值赋值给名为  type  的变量,以便后续在同一作用域内使用该变量。具体而言:
 th:with  是 Thymeleaf 的一个属性,用于定义一个局部变量。
 type  是变量的名称,可以根据实际情况任意命名。
 $${@dict.getType('biz_article_type')}  是 Thymeleaf 表达式,表示调用一个名为  getType  的工具类方法,并将返回值作为变量  type  的值。
 @dict  是 Thymeleaf 工具类的实例化对象,用于操作字典数据。 .getType('biz_article_type')  表示调用该对象的  getType  方法,并传递  'biz_article_type'  这个字典类型作为参数。该方法的返回值是一个包含字典数据的列表。
最终将该列表赋值给  type  变量,以便在后续 Thymeleaf 表达式中引用。
-->
<option value="">所有</option>
<option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option>
<!--

 th:each="dict : $${type}"  表示遍历  type  这个变量,将每个元素赋值给  dict  这个变量。
 th:text="$${dict.dictLabel}"  表示将  dict  对象中的  dictLabel  属性值作为该选项的文本值。
 th:value="$${dict.dictValue}"  表示将  dict  对象中的  dictValue  属性值作为该选项的值。
最终渲染出来的 HTML 代码类似于这样:

 
<select name="categoryId">
<option value="">所有</option>
<option value="1">政治</option>
<option value="2">经济</option>
<option value="3">科技</option>
...
</select>
 

其中  1 、 2 、 3  等为具体的字典值(即选项的值), 政治 、 经济 、 科技  等为字典标签(即选项的文本)。

-->
</select>
</li>
<li>
<label>文章状态:</label>
<select name="articleStatus" th:with="type=${@dict.getType('article_status')}">
<option value="">所有</option>
<option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option>
</select>
</li>
<li>
<label>审核人员ID:</label>
<input type="text" name="articleAuditUserid"/>
</li>
<li>
<label>审核人员用户名:</label>
<input type="text" name="articleAuditUsername"/>
</li>
<li>
<label>排序:</label>
<input type="text" name="sort"/>
</li>
<li>
<a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;搜索</a>
<a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;重置</a>
</li>
</ul>
</div>
</form>
</div>
<!-- 增删改查按钮 -->
<div class="btn-group-sm" id="toolbar" role="group">
<a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="biz:article:add">
<i class="fa fa-plus"></i> 添加
</a>
<a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="biz:article:edit">
<i class="fa fa-edit"></i> 修改
</a>
<a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="biz:article:remove">
<i class="fa fa-remove"></i> 删除
</a>
<a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="biz:article:export">
<i class="fa fa-download"></i> 导出
</a>
</div>
<!-- 表格 -->
<div class="col-sm-12 select-table table-striped">
<table id="bootstrap-table"></table>
</div>
</div>
</div>
<th:block th:include="include :: footer" />
<script th:inline="javascript">
var editFlag = [[${@permission.hasPermi('biz:article:edit')}]]; //表示定义一个 JavaScript 变量  editFlag ,并将后端 Java 方法  hasPermi('biz:article:edit')  的返回值赋值给该变量。其中, $${}  表示 Thymeleaf 表达式,在此使用该表达式调用  hasPermi  方法,该方法接受一个权限标识符,并返回一个布尔值,表示当前用户是否拥有该权限。注意该表达式使用了双重  [[...]]  嵌套,是为了解决 JavaScript 和 Thymeleaf 表达式双重嵌套的问题。
var removeFlag = [[${@permission.hasPermi('biz:article:remove')}]];
var categoryIdDatas = [[${@dict.getType('biz_article_type')}]];
var articleStatusDatas = [[${@dict.getType('article_status')}]];
var prefix = ctx + "biz/article"; //表示定义一个名为  prefix  的常量,赋值为  ctx + "biz/article" ,其中, ctx  是后端向模板中添加的  contextPath  变量,表示应用程序上下文路径。该常量用于在 JavaScript 中定义请求路径,实现前后端交互


$(function() {
var options = {
url: prefix + "/list",
createUrl: prefix + "/add",
updateUrl: prefix + "/edit/{id}",
removeUrl: prefix + "/remove",
exportUrl: prefix + "/export",
modalName: "文章管理",
columns: [{
checkbox: true
},
{
field: 'articaleId',
title: '文章ID',
visible: false
},
{
field: 'articleTitle',
title: '文章标题'
},
{
field: 'articleContent',
title: '文章内容'
},
{
field: 'articleImg',
title: '文章封面'
},
{
field: 'deptId',
title: '部门ID'
},
{
field: 'categoryId',
title: '文章类别',
//字典值查字典标签
formatter: function(value, row, index) {
return $.table.selectDictLabel(categoryIdDatas, value);
}
/*
 formatter  是 Bootstrap Table 中的一个参数,用于自定义单元格数据的呈现方式。
 value  表示当前单元格的值,可以是任何类型。
 row  表示当前行的数据,是一个对象。
 index  表示当前行的索引值,从 0 开始。
 $$.table  是 Bootstrap Table 团队封装的一个工具方法,用于处理常见的表格操作。可以在  table.js  文件中找到这个对象的实现。
 selectDictLabel  是该工具方法中的一个子方法,用于将字典值转换为字典标签。具体而言,它接受两个参数,其中  categoryIdDatas  表示一个字典数据列表, value  表示要查询的字典值。函数会遍历字典数据,查找与  value  相等的项,并返回其  dictLabel  属性值。
 categoryIdDatas  通常由后端代码通过  Model  或  ModelAndView  对象传递到前端视图层,以便在表格中使用。在数据列表中,通常会将字典值和字典标签一一对应。
最终将返回值作为单元格的显示内容。
*/
},
{
field: 'articleStatus',
title: '文章状态',
formatter: function(value, row, index) {
return $.table.selectDictLabel(articleStatusDatas, value);
}
},
{
field: 'articleAuditUserid',
title: '审核人员ID'
},
{
field: 'articleAuditUsername',
title: '审核人员用户名'
},
{
field: 'sort',
title: '排序'
},
{
field: 'remark',
title: '备注'
},
{
title: '操作',
align: 'center',
formatter: function(value, row, index) {
var actions = [];
actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.articaleId + '\')"><i class="fa fa-edit"></i>编辑</a> ');
actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.articaleId + '\')"><i class="fa fa-remove"></i>删除</a>');
return actions.join('');
}
}]
};
$.table.init(options);
});
</script>
</body>
</html>

 

add.html 添加文章表单页面
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
    <th:block th:include="include :: header('新增文章管理')" />
    <th:block th:include="include :: bootstrap-fileinput-css"/>
    <th:block th:include="include :: summernote-css" />
</head>
<body class="white-bg">
    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
        <form class="form-horizontal m" id="form-article-add">
            <div class="form-group">    
                <label class="col-sm-3 control-label is-required">文章标题:</label>
                <div class="col-sm-8">
                    <input name="articleTitle" class="form-control" type="text" required>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">文章封面:</label>
                <div class="col-sm-8">
                    <input type="hidden" name="articleImg">
                    <div class="file-loading">
                        <input class="form-control file-upload" id="articleImg" name="file" type="file">
                    </div>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label is-required">文章内容:</label>
                <div class="col-sm-8">
                    <input type="hidden" class="form-control" name="articleContent">
                    <div class="summernote" id="articleContent"></div>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">部门ID:</label>
                <div class="col-sm-8">
                    <input name="deptId" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">文章类别:</label>
                <div class="col-sm-8">
                    <select name="categoryId" class="form-control m-b" th:with="type=${@dict.getType('biz_article_type')}">
                        <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option>
                    </select>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label is-required">文章状态:</label>
                <div class="col-sm-8">
                    <select name="articleStatus" class="form-control m-b" th:with="type=${@dict.getType('article_status')}" required>
                        <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option>
                    </select>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">审核人员ID:</label>
                <div class="col-sm-8">
                    <input name="articleAuditUserid" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">审核人员用户名:</label>
                <div class="col-sm-8">
                    <input name="articleAuditUsername" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">排序:</label>
                <div class="col-sm-8">
                    <input name="sort" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">
                <label class="col-sm-3 control-label">备注:</label>
                <div class="col-sm-8">
                    <textarea name="remark" class="form-control"></textarea>
                </div>
            </div>
        </form>
    </div>
    <th:block th:include="include :: footer" />
    <th:block th:include="include :: bootstrap-fileinput-js"/>
    <th:block th:include="include :: summernote-js" />
    
    <!--这段代码主要用于实现前后端的数据交互、表单验证和文件上传,在 Thymeleaf 模板中内嵌 JavaScript 脚本,通过 jQuery 提供的插件和方法实现前端交互。-->
    <script th:inline="javascript">  <!--表示将脚本标签转换为内嵌 JavaScript 脚本标签,使得 Thymeleaf 表达式可以被 JavaScript 代码正确解析。-->
        var prefix = ctx + "biz/article"
        $("#form-article-add").validate({
            focusCleanup: true
        });
/*
是一个 jQuery 插件,用于在前端校验表单数据,确保输入的数据符合要求。该方法中的  focusCleanup  表示在焦点改变时是否清除错误信息。
*/
        function submitHandler() {
            if ($.validate.form()) {
                $.operate.save(prefix + "/add", $('#form-article-add').serialize());
            }
        }
/*
定义了一个名为  submitHandler  的 JavaScript 函数,用于表单数据提交,当表单验证通过时,会自动调用该方法,向后台发送数据。
*/
        $(".file-upload").fileinput({
            uploadUrl: ctx + 'common/upload',
            maxFileCount: 1,
            autoReplace: true
        }).on('fileuploaded', function (event, data, previewId, index) {
            $("input[name='" + event.currentTarget.id + "']").val(data.response.url)
        }).on('fileremoved', function (event, id, index) {
            $("input[name='" + event.currentTarget.id + "']").val('')
        })
/*
 是一个文件上传 jQuery 插件,用于在前端上传文件,其中  uploadUrl  表示文件上传的 URL 路径, maxFileCount  表示最大上传文件数, autoReplace  表示是否自动替换已有文件。

 on('fileuploaded', function {...})  监听文件上传成功事件,当文件上传成功后,会自动调用该方法将上传成功的文件的 URL 填入  input  元素中。
 on('fileremoved', function {...})  监听文件删除事件,当文件被删除后,会自动调用该方法将文件 URL 清空。

*/

//这段代码主要用于配置 Summernote 富文本编辑器,以及处理文本框内容改变和图片上传时的回调函数,从而实现前后端数据交互和富文本编辑。
        $(function() {
            $('.summernote').summernote({//表示选择所有含有  summernote  类的 HTML 元素,调用 Summernote 富文本编辑器进行初始化。其中, lang  表示语言,这里设置为中文; callbacks  表示回调函数列表,包括当文本框内容改变时和上传图片时的回调函数。
                lang: 'zh-CN',
                callbacks: {
                    onChange: function(contents, $edittable) {
                        $("input[name='" + this.id + "']").val(contents);
                    },//表示当文本框内容改变时的回调函数,其中  contents  表示当前文本框内容, $$edittable  表示当前 Summernote 实例对象,该函数的作用是将文本框内容设置为  input  元素的值
                    onImageUpload: function(files) {
                        var obj = this;
                        var data = new FormData();
                        data.append("file", files[0]);
                        $.ajax({
                            type: "post",
                            url: ctx + "common/upload",
                            data: data,
                            cache: false,
                            contentType: false,
                            processData: false,
                            dataType: 'json',
                            success: function(result) {
                                if (result.code == web_status.SUCCESS) {
                                    $('#' + obj.id).summernote('insertImage', result.url);
                                } else {
                                    $.modal.alertError(result.msg);
                                }
                            },
                            error: function(error) {
                                $.modal.alertWarning("图片上传失败。");
                            }
                        });
                    }//表示当上传图片时的回调函数,其中  files  表示上传的文件列表。该函数的作用是将上传的文件列表打包成  FormData  数据,然后通过 AJAX 方式向后台发送数据请求。在请求成功后,如果返回的 JSON 数据中的  code  为  SUCCESS ,则通过 Summernote 的 API 插入图片,否则通过  $$.modal.alertError(result.msg)  方法提示错误信息。
                }
            });
        });
    </script>
</body>
</html>

 

 

这段代码是一个 Thymeleaf 模板中的 HTML 表单代码,用于创建一个名为  form-article-edit  的表单,具体而言:

 

 

edit.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
<head>
    <th:block th:include="include :: header('修改文章管理')" />
    <th:block th:include="include :: bootstrap-fileinput-css"/>
    <th:block th:include="include :: summernote-css" />
</head>
<body class="white-bg">
    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
<!--总的来说,这段代码主要用于在 HTML 中定义一个表单元素,并将后端数据模型对象与之进行绑定,方便后续在 JS 中对其进行处理。
-->
<form class="form-horizontal m" id="form-article-edit" th:object="${bizArticle}"><!--

 <form>  表示定义一个 HTML 表单元素。
 class="form-horizontal m"  表示该表单的 CSS 类名,用于样式布局。
 id="form-article-edit"  表示该表单的 ID,可以用于 JS 脚本中对其进行操作。
 th:object="$${bizArticle}"  表示该表单的数据绑定对象,使用 Thymeleaf 表达式  $${}  表示在表单中绑定后端的  bizArticle  对象,其中  bizArticle  在控制器中传到前端视图层的名称。该表达式使用了 Thymeleaf 的  th:object  属性,表示绑定数据模型对象。


 

-->
            <input name="articaleId" th:field="*{articaleId}" type="hidden">
            <div class="form-group">    
                <label class="col-sm-3 control-label is-required">文章标题:</label>
                <div class="col-sm-8">
                    <input name="articleTitle" th:field="*{articleTitle}" class="form-control" type="text" required>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">文章封面:</label>
                <div class="col-sm-8">
                    <input type="hidden" name="articleImg" th:field="*{articleImg}">
                    <div class="file-loading">
                        <input class="form-control file-upload" id="articleImg" name="file" type="file">
                    </div>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label is-required">文章内容:</label>
                <div class="col-sm-8">
                    <input type="hidden" class="form-control" th:field="*{articleContent}">
                    <div class="summernote" id="articleContent"></div>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">部门ID:</label>
                <div class="col-sm-8">
                    <input name="deptId" th:field="*{deptId}" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">文章类别:</label>
                <div class="col-sm-8">
                    <select name="categoryId" class="form-control m-b" th:with="type=${@dict.getType('biz_article_type')}">
                        <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}" th:field="*{categoryId}"></option>
                    </select>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label is-required">文章状态:</label>
                <div class="col-sm-8">
                    <select name="articleStatus" class="form-control m-b" th:with="type=${@dict.getType('article_status')}" required>
                        <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}" th:field="*{articleStatus}"></option>
                    </select>
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">审核人员ID:</label>
                <div class="col-sm-8">
                    <input name="articleAuditUserid" th:field="*{articleAuditUserid}" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">审核人员用户名:</label>
                <div class="col-sm-8">
                    <input name="articleAuditUsername" th:field="*{articleAuditUsername}" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">    
                <label class="col-sm-3 control-label">排序:</label>
                <div class="col-sm-8">
                    <input name="sort" th:field="*{sort}" class="form-control" type="text">
                </div>
            </div>
            <div class="form-group">
                <label class="col-sm-3 control-label">备注:</label>
                <div class="col-sm-8">
                    <textarea name="remark" class="form-control">[[*{remark}]]</textarea>
                </div>
            </div>
        </form>
    </div>
    <th:block th:include="include :: footer" />
    <th:block th:include="include :: bootstrap-fileinput-js"/>
    <th:block th:include="include :: summernote-js" />
    <script th:inline="javascript">
        var prefix = ctx + "biz/article";
        $("#form-article-edit").validate({
            focusCleanup: true
        });

        function submitHandler() {
            if ($.validate.form()) {
                $.operate.save(prefix + "/edit", $('#form-article-edit').serialize());
            }
        }

        $(".file-upload").each(function (i) {
            var val = $("input[name='" + this.id + "']").val()
            $(this).fileinput({
                'uploadUrl': ctx + 'common/upload',
                initialPreviewAsData: true,
                initialPreview: [val],
                maxFileCount: 1,
                autoReplace: true
            }).on('fileuploaded', function (event, data, previewId, index) {
                $("input[name='" + event.currentTarget.id + "']").val(data.response.url)
            }).on('fileremoved', function (event, id, index) {
                $("input[name='" + event.currentTarget.id + "']").val('')
            })
            $(this).fileinput('_initFileActions');
        });

        $(function() {
            $('.summernote').each(function(i) {
                $('#' + this.id).summernote({
                    lang: 'zh-CN',
                    callbacks: {
                        onChange: function(contents, $edittable) {
                            $("input[name='" + this.id + "']").val(contents);
                        },
                        onImageUpload: function(files) {
                            var obj = this;
                            var data = new FormData();
                            data.append("file", files[0]);
                            $.ajax({
                                type: "post",
                                url: ctx + "common/upload",
                                data: data,
                                cache: false,
                                contentType: false,
                                processData: false,
                                dataType: 'json',
                                success: function(result) {
                                    if (result.code == web_status.SUCCESS) {
                                        $('#' + obj.id).summernote('insertImage', result.url);
                                    } else {
                                        $.modal.alertError(result.msg);
                                    }
                                },
                                error: function(error) {
                                    $.modal.alertWarning("图片上传失败。");
                                }
                            });
                        }
                    }
                });
                var content = $("input[name='" + this.id + "']").val();
                $('#' + this.id).summernote('code', content);
            })
        });
    </script>
</body>
</html>

 

posted on 2023-04-21 07:42  GKLBB  阅读(440)  评论(0)    收藏  举报