文章目录

    • 一、前言
    • 二、效果
    • 三、编码过程
      • 1.前端:
        • index.vue
        • projectShow.js
        • 富文本框: Editor/index.vue
        • 图片上传:ImgUploadCropper/index.vue
      • 2.后端:
        • 实体ProjectShow
        • ProjectShowController
        • IProjectShowService
        • ProjectShowServiceImpl
        • ProjectShowMapper
        • ProjectShowMapper.xml

一、前言

现在的需求是:实现一个项目展示模块,后端管理页面除了需要基础信息外,要加上一个图片上传和富文本框编辑器功能

二、效果


点击”图片存储地址”:可上传电脑任何位置的图片,并可对图片进行放大,缩小,和旋转。



存入数据库的图片以url地址存放

url直接百度可看到图片:

三、编码过程

1.前端:

index.vue
<template><div class="app-container"><el-row :gutter="10" class="mb8"><el-col :span="1.5"><el-buttontype="primary"plainicon="el-icon-plus"size="mini"@click="handleAdd">新增</el-button></el-col></el-row><el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body><el-form ref="formObj" :model="form" :rules="rules" label-width="120px" ><el-form-item label="项目名称" prop="projectName"><el-input v-model="form.projectName" placeholder="请输入项目名称" /></el-form-item><el-form-item label="项目类型" prop="projectType"><el-selectv-model="form.projectType"placeholder="请选择项目类型"style="width: 65%"><el-optionv-for="dict in projectTypeOptions":key="dict.dictValue":label="dict.dictLabel":value="dict.dictValue"></el-option></el-select></el-form-item><el-form-item prop="picUrl" label="图片存储地址"required><div class="coverImg-upload" @click="showCoverImgCropper = true"><img v-if="form.picUrl" :src="form.picUrl" class="coverImg" /><i v-else class="el-icon-plus coverImg-upload-icon" /></div></el-form-item><el-form-item prop="projectDetail" label="项目详情"><my-quill-editor v-model="form.projectDetail" ref="quillEditor" /></el-form-item><el-form-item label="备注" prop="remark"><el-inputv-model="form.remark"type="textarea"placeholder="请输入备注"/></el-form-item></el-form><img-upload-cropper:visible.sync="showCoverImgCropper"@upload-success="onCoverImgUploaded"/><div slot="footer" class="dialog-footer"><el-button type="primary" @click="submitForm">确 定</el-button><el-button @click="cancel">取 消</el-button></div></el-dialog><el-tablev-loading="loading":data="projectShowList"row-key="id"default-expand-all:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"><el-table-column label="项目名称" align="center" prop="projectName" /><el-table-columnlabel="图片存储地址"align="center"prop="picUrl"v-if="false"/><el-table-columnlabel="项目详情"align="center"prop="projectDetail"v-if="false"/><el-table-columnlabel="项目类型"align="center"prop="projectType":formatter="projectTypeFormat"/><el-table-column label="创建人" align="center" prop="createUser" /><el-table-column label="创建时间" align="center" prop="createTime" /><el-table-column label="修改人" align="center" prop="updateUser" /><el-table-column label="修改时间" align="center" prop="updateTime" /><el-table-column label="备注" align="center" prop="remark"/><el-table-columnlabel="操作"align="center"class-name="small-padding fixed-width"><template slot-scope="scope"><el-buttonsize="mini"type="text"icon="el-icon-edit"@click="handleUpdate(scope.row)">修改</el-button><el-buttonsize="mini"type="text"icon="el-icon-delete"@click="handleDelete(scope.row)">删除</el-button></template></el-table-column></el-table></div></template><script>import {listProjectShow,addProjectShow,updateProjectShow,getProjectShow,delProjectShow,} from "@/api/projectShow/projectShow";import myQuillEditor from "@/components/Editor";import ImgUploadCropper from "@/components/ImgUploadCropper";export default {name: "cpsp",components: {myQuillEditor,ImgUploadCropper,},data() {return {// 遮罩层loading: true,// 资产分类表格数据projectShowList: [],//计费方式字典projectTypeOptions: [],// 弹出层标题title: "",// 资产分类树选项categoryOptions: [],// 是否显示弹出层open: false,// 表单参数form: {id: null,projectName: null,projectType: "1",picUrl: "",projectDetail: "",remark: null,},showCoverImgCropper: false,formObj: "",// 表单校验rules: {projectName: [{ required: true, message: "项目名称不能为空", trigger: "blur" },],projectType: [{ required: true, message: "项目类型不能为空", trigger: "blur" },],picUrl: [{ required: true, trigger: "change", message: "图片存储地址不能为空" },],},};},mounted() {this.formObj = this.$refs.formObj;},created() {this.getList();this.getDicts("project_show_type").then((response) => {this.projectTypeOptions = response.data;});},methods: {/** 查询资产分类列表 */getList() {this.loading = true;listProjectShow(this.queryParams).then((response) => {this.projectShowList = response.data;this.loading = false;});},// 项目类型字典翻译projectTypeFormat(row, column) {return this.selectDictLabel(this.projectTypeOptions, row.projectType);},// 取消按钮cancel() {this.open = false;this.reset();},// 表单重置reset() {this.form = {id: null,projectName: null,projectType: "1",picUrl: "",projectDetail: "",remark: null,};this.resetForm("formObj");},/** 新增按钮操作 */handleAdd() {this.reset();this.open = true;this.title = "添加项目";},/** * 组件封面图片上传 */ onCoverImgUploaded(picUrl) {this.form.picUrl = picUrl;// 清除表单校验红字this.formObj.clearValidate("picUrl");},/** 提交按钮 */submitForm() {this.$refs["formObj"].validate((valid) => {if (valid) {if (this.form.id != null) {updateProjectShow(this.form).then((response) => {this.msgSuccess("修改成功");this.open = false;this.getList();});} else {addProjectShow(this.form).then((response) => {this.msgSuccess("新增成功");this.open = false;this.getList();console.log(this.form);});}}});},/** 修改按钮操作 */handleUpdate(row) {this.reset();getProjectShow(row.id).then((response) => {this.form = response.data;this.open = true;this.title = "修改项目展示内容";});},/** 删除按钮操作 */handleDelete(row) {this.$confirm('是否确认删除项目名为"' + row.projectName + '"的数据项" />, "警告", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(function () {return delProjectShow(row.id);}).then(() => {this.getList();this.msgSuccess("删除成功");});},},};</script><style lang="scss">.coverImg-upload {margin-top: 10px;width: 150px;height: 150px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;img {width: 100%;height: 100%;}.coverImg-upload-icon {font-size: 28px;color: #8c939d;width: 150px;height: 150px;line-height: 150px;text-align: center;}}</style>
projectShow.js
import request from '@/utils/request'// 查询项目展示列表export function listProjectShow(query) {return request({url: '/projectShow/list',method: 'get',params: query})}// 新增项目展示export function addProjectShow(data) {return request({url: '/projectShow',method: 'post',data: data})}// 修改项目展示export function updateProjectShow(data) {return request({url: '/projectShow',method: 'put',data: data})}// 点击修改按钮获取到具体cpsp项目的详情export function getProjectShow(id) {return request({url: '/projectShow/' + id,method: 'get'})}// 删除资产分类export function delProjectShow(id) {return request({url: '/projectShow/' + id,method: 'delete'})}
富文本框: Editor/index.vue
<template><div><el-uploadclass="avatar-uploader quill-img":action="uploadImgUrl"name="file":headers="headers":show-file-list="false":on-success="quillImgSuccess":on-error="uploadError":before-upload="quillImgBefore"accept='.jpg,.jpeg,.png,.gif'></el-upload><quill-editorclass="editor"v-model="content"ref="quillEditor":options="editorOption"@blur="onEditorBlur($event)"@focus="onEditorFocus($event)"@change="onEditorChange($event)"></quill-editor></div></template><script>import { getToken } from '@/utils/auth'// 工具栏配置const toolbarOptions = [["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线["blockquote", "code-block"],// 引用代码块[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表[{ indent: "-1" }, { indent: "+1" }],// 缩进[{ size: ["small", false, "large", "huge"] }], // 字体大小[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色[{ align: [] }], // 对齐方式["clean"], // 清除文本格式["link", "image", "video"] // 链接、图片、视频];import { quillEditor } from "vue-quill-editor";import "quill/dist/quill.core.css";import "quill/dist/quill.snow.css";import "quill/dist/quill.bubble.css";export default {model: {prop: "value",event: "change"},props: {/* 编辑器的内容 */value: {type: String},/* 图片大小 */maxSize: {type: Number,default: 4000 //kb}},components: { quillEditor },data() {return {content: this.value,editorOption: {placeholder: "",theme: "snow", // or 'bubble'placeholder: "请输入内容",modules: {toolbar: {container: toolbarOptions,handlers: {image: function(value) {if (value) {// 触发input框选择图片文件document.querySelector(".quill-img input").click();} else {this.quill.format("image", false);}}}}}},// uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址uploadImgUrl: process.env.VUE_APP_BASE_API + "/system/file/upload",headers: {Authorization: 'Bearer ' + getToken()}};},watch: {value: function() {this.content = this.value;}},methods: {onEditorBlur() {//失去焦点事件},onEditorFocus() {//获得焦点事件},onEditorChange() {//内容改变事件this.$emit("change", this.content);},// 富文本图片上传前quillImgBefore(file) {let fileType = file.type;if(fileType === 'image/jpeg' || fileType === 'image/png'){return true;}else {this.$message.error('请插入图片类型文件(jpg/jpeg/png)');return false;}},quillImgSuccess(res, file) {// res为图片服务器返回的数据// 获取富文本组件实例let quill = this.$refs.quillEditor.quill;// 如果上传成功if (res.code == 200) {// 获取光标所在位置let length = quill.getSelection().index;// 插入图片res.url为服务器返回的图片地址quill.insertEmbed(length, "image", res.url);// 调整光标到最后quill.setSelection(length + 1);} else {this.$message.error("图片插入失败");}},// 富文本图片上传失败uploadError() {// loading动画消失this.$message.error("图片插入失败");}}};</script> <style>.editor {line-height: normal !important;/* height: 192px; */}.quill-img {display: none;}.ql-snow .ql-tooltip[data-mode="link"]::before {content: "请输入链接地址:";}.ql-snow .ql-tooltip.ql-editing a.ql-action::after {border-right: 0px;content: "保存";padding-right: 0px;}.ql-snow .ql-tooltip[data-mode="video"]::before {content: "请输入视频地址:";}.ql-snow .ql-picker.ql-size .ql-picker-label::before,.ql-snow .ql-picker.ql-size .ql-picker-item::before {content: "14px";}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {content: "10px";}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {content: "18px";}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {content: "32px";}.ql-snow .ql-picker.ql-header .ql-picker-label::before,.ql-snow .ql-picker.ql-header .ql-picker-item::before {content: "文本";}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {content: "标题1";}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {content: "标题2";}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {content: "标题3";}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {content: "标题4";}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {content: "标题5";}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {content: "标题6";}.ql-snow .ql-picker.ql-font .ql-picker-label::before,.ql-snow .ql-picker.ql-font .ql-picker-item::before {content: "标准字体";}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {content: "衬线字体";}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {content: "等宽字体";}</style>
图片上传:ImgUploadCropper/index.vue
<template><el-dialogclass="img-upload-cropper":title="title":visible.sync="show"width="800px"append-to-body@close="onDialogClose"><el-row><el-col :xs="24" :md="12" :style="{ height: '350px' }"><vue-cropperref="cropper":img="options.img"outputType="png":info="true":autoCrop="options.autoCrop":autoCropWidth="options.autoCropWidth":autoCropHeight="options.autoCropHeight":fixedBox="options.fixedBox"@realTime="realTime"/></el-col><el-col :xs="24" :md="12" :style="{ height: '350px' }"><divclass="upload-preview":style="`width:${options.autoCropWidth}px;height:${options.autoCropHeight}px;border-radius:${previewBorderRaidus}`"><img :src="previews.url" :style="previews.img" /></div></el-col></el-row><br /><el-row><el-col :lg="2" :md="2"><el-uploadaction="#":http-request="httpRequest":show-file-list="false":before-upload="beforeUpload"><el-button size="small">上传<i class="el-icon-upload el-icon--right"></i></el-button></el-upload></el-col><el-col :lg="{ span: 1, offset: 2 }" :md="2"><el-buttonicon="el-icon-plus"size="small"@click="changeScale(1)"></el-button></el-col><el-col :lg="{ span: 1, offset: 1 }" :md="2"><el-buttonicon="el-icon-minus"size="small"@click="changeScale(-1)"></el-button></el-col><el-col :lg="{ span: 1, offset: 1 }" :md="2"><el-buttonicon="el-icon-refresh-left"size="small"@click="rotateLeft()"></el-button></el-col><el-col :lg="{ span: 1, offset: 1 }" :md="2"><el-buttonicon="el-icon-refresh-right"size="small"@click="rotateRight()"></el-button></el-col><el-col :lg="{ span: 2, offset: 6 }" :md="2"><el-button type="primary" size="small" @click="uploadImg()">提 交</el-button></el-col></el-row></el-dialog></template><script>import { VueCropper } from "vue-cropper";import { fileUpload } from "@/api/system/upload";import { uploadAvatar } from "@/api/system/user";export default {name: "img-upload-cropper",components: { VueCropper },props: {visible: {type: Boolean,default: false,},title: {type: String,default: "",},compType: {type: String,default: "",},/** * 右边预览图的border-radius,单位自定 */previewBorderRaidus: {type: String,default: "",},},computed: {},watch: {visible(val) {this.show = val;},},data() {return {options: {img: "", //裁剪图片的地址autoCrop: true, // 是否默认生成截图框autoCropWidth: 200, // 默认生成截图框宽度autoCropHeight: 200, // 默认生成截图框高度fixedBox: true, // 固定截图框大小 不允许改变},show: false,previews: {},};},created() {},mounted() {},methods: {/** * 关闭时 */onDialogClose() {this.$emit("update:visible", false);},/** * 图片上传之前 */beforeUpload(file) {if (file.type.indexOf("image/") == -1) {this.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");} else {const reader = new FileReader();reader.readAsDataURL(file);reader.onload = () => {this.options.img = reader.result;};}},/** * 上传到服务器 */uploadImg() {this.$refs.cropper.getCropBlob((data) => {let formData = new FormData();if (this.compType === "avatar") {// 头像上传formData.append("avatarfile", data);uploadAvatar(formData).then((response) => {console.log(" ~ file: index.vue ~ line 161 ~ uploadAvatar ~ response",response);if (response.code === 200) {this.show = false;this.options.img = "";this.$emit("upload-success", response.imgUrl);this.msgSuccess("修改成功");}});} else {formData.append("file", data);fileUpload(formData).then((response) => {if (response.code === 200) {// this.$refs.cropper.clearCrop();this.show = false;this.options.img = "";this.$emit("upload-success", response.url);this.msgSuccess("上传成功");}});}});},// 向左旋转rotateLeft() {this.$refs.cropper.rotateLeft();},// 向右旋转rotateRight() {this.$refs.cropper.rotateRight();},// 图片缩放changeScale(num) {num = num || 1;this.$refs.cropper.changeScale(num);},// 实时预览realTime(data) {this.previews = data;},/** * 覆盖默认的上传行为,可以自定义上传的实现 * 留空即可,不写这个的话会有点报错 */httpRequest() {},},};</script><style lang="scss" scoped>.img-upload-cropper {.upload-preview {position: absolute;top: 50%;transform: translate(50%, -50%);border-radius: 0;box-shadow: 0 0 4px #ccc;overflow: hidden;}}</style>

2.后端:

实体ProjectShow
@Datapublic class ProjectShow {/** 自增长主键ID */private Long id;/** 项目名称 */@NotNull(message = "项目名称不能为空")private String projectName;/** 项目类型*/@NotNull(message = "项目类型不能为空")private String projectType;/** 图片路径 */@NotNull(message = "图片路径不能为空")private String picUrl;/** 项目详情*/@NotNull(message = "项目详情不能为空")private String projectDetail;/** 创建人 */@NotNull(message = "创建人不能为空")private String createUser;/** 创建日期*/@JsonFormat(pattern = "yyyy-MM-dd")private Date createTime;/** 更新人 */private String updateUser;/** 更新日期*/@JsonFormat(pattern = "yyyy-MM-dd")private Date updateTime;/** 备注 */private String remark;}
ProjectShowController
@RestController@RequestMapping("/projectShow")public class ProjectShowController extends BaseController {@Autowiredprivate IProjectShowService iProjectShowService;@GetMapping("/list")public AjaxResult list(ProjectShow projectShow) {List<ProjectShow> list = iProjectShowService.selectProjectShowList(projectShow);returnAjaxResult.success(list);}@PostMappingpublic AjaxResult add(@RequestBody ProjectShow projectShow) {return toAjax(iProjectShowService.insertProjectShow(projectShow));}/** * 修改 */@PutMappingpublic AjaxResult edit(@RequestBody ProjectShow projectShow) {return toAjax(iProjectShowService.updateProjectShow(projectShow));}/** * 点击修改按钮后获项目展示的详细信息 */@GetMapping(value = "/{id}")public AjaxResult getInfo(@PathVariable("id") Long id) {return AjaxResult.success(iProjectShowService.selectProjectShowById(id));}/** * 删除 */@DeleteMapping("/{ids}")public AjaxResult remove(@PathVariable Long[] ids) {return toAjax(iProjectShowService.deleteProjectShowByIds(ids));}}
IProjectShowService
public interface IProjectShowService {public List<ProjectShow> selectProjectShowList(ProjectShow projectShow);public int insertProjectShow(ProjectShow projectShow);public int updateProjectShow(ProjectShow projectShow);public ProjectShowselectProjectShowById(Long id);public int deleteProjectShowByIds(Long[] ids);}
ProjectShowServiceImpl
@Service@Slf4jpublic class ProjectShowServiceImplimplements IProjectShowService {@Autowiredprivate ProjectShowMapper projectShowMapper;@Autowiredprivate TokenService tokenService;@Overridepublic List<ProjectShow> selectProjectShowList(ProjectShow projectShow) {return projectShowMapper.selectProjectShowList(projectShow);}@Overridepublic int insertProjectShow(ProjectShow projectShow) {LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());SysUser user = loginUser.getUser();projectShow.setCreateUser(user.getUserName());projectShow.setCreateTime(new Date());return projectShowMapper.insertProjectShow(projectShow);}@Overridepublic int updateProjectShow(ProjectShow projectShow) {LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());SysUser user = loginUser.getUser();projectShow.setUpdateUser(user.getUserName());projectShow.setUpdateTime(new Date());returnprojectShowMapper.updateProjectShow(projectShow);}@Overridepublic ProjectShow selectProjectShowById(Long id) {return projectShowMapper.selectProjectShowById(id);}@Overridepublic int deleteProjectShowByIds(Long[] ids) {return projectShowMapper.deleteProjectShowByIds(ids);}}
ProjectShowMapper
@Repositorypublic interface ProjectShowMapper {public List<ProjectShow> selectProjectShowList(ProjectShow projectShow);public List<ProjectShow> selectProjectShowList();public int insertProjectShow(ProjectShow projectShow);//修改public int updateProjectShow(ProjectShow projectShow);public ProjectShow selectProjectShowById(Long id);public int deleteProjectShowByIds(Long[] ids);}
ProjectShowMapper.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.activate.module.projectshow.mapper.ProjectShowMapper"><resultMap type="com.activate.module.projectshow.domain.ProjectShow" id="ProjectShowResult"><result property="id" column="id"/><result property="projectName" column="project_name"/><result property="projectType" column="project_type"/><result property="picUrl" column="pic_url"/><result property="projectDetail" column="project_detail"/><result property="createUser" column="create_user"/><result property="createTime" column="create_time"/><result property="updateUser" column="update_user"/><result property="updateTime" column="update_time"/><result property="remark" column="remark"/></resultMap><sql id="selectProjectShowVo">select id, project_name, project_type, pic_url, project_detail, create_user, create_time ,update_user ,update_time ,remark from project_show</sql><select id="selectProjectShowList" parameterType="com.activate.module.projectshow.domain.ProjectShow" resultMap="ProjectShowResult"><include refid="selectProjectShowVo"/></select><select id="selectProjectShowById" parameterType="Long" resultMap="ProjectShowResult"><include refid="selectProjectShowVo"/>where id = #{id}</select><insert id="insertProjectShow" parameterType="com.activate.module.projectshow.domain.ProjectShow" useGeneratedKeys="true"keyProperty="id">insert into project_show<trim prefix="(" suffix=")" suffixOverrides=","><if test="projectName != null and projectName != ''">project_name,</if><if test="projectType != null and projectType != ''">project_type,</if><if test="picUrl != null ">pic_url,</if><if test="projectDetail != null ">project_detail,</if><if test="createUser != null ">create_user,</if><if test="createTime != null ">create_time,</if><if test="updateUser != null ">update_user,</if><if test="updateTime != null ">update_time,</if><if test="remark != null ">remark,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="projectName != null and projectName != ''">#{projectName},</if><if test="projectType != null and projectType != ''">#{projectType},</if><if test="picUrl != null">#{picUrl},</if><if test="projectDetail != null">#{projectDetail},</if><if test="createUser != null">#{createUser},</if><if test="createTime != null ">#{createTime},</if><if test="updateUser != null ">#{updateUser},</if><if test="updateTime != null ">#{updateTime},</if><if test="remark != null ">#{remark},</if></trim></insert><update id="updateProjectShow" parameterType="com.activate.module.projectshow.domain.ProjectShow">update project_show<trim prefix="SET" suffixOverrides=","><if test="projectName != null and projectName != ''">project_name=#{projectName},</if><if test="projectType != null and projectType != ''">project_type=#{projectType},</if><if test="picUrl != null">pic_url=#{picUrl},</if><if test="projectDetail != null">project_detail=#{projectDetail},</if><if test="createUser != null">create_user=#{createUser},</if><if test="createTime != null ">create_time=#{createTime},</if><if test="updateUser != null ">update_user=#{updateUser},</if><if test="updateTime != null ">update_time=#{updateTime},</if><if test="remark != null ">remark=#{remark},</if></trim>where id = #{id}</update><delete id="deleteProjectShowByIds" parameterType="String">delete from project_show where id in<foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach></delete></mapper>