<div> <el-input type="text" placeholder="在此输入标题" v-model="title" maxlength="60" show-word-limit > </el-input> <br> <br> </div> <quill-editor v-model="editContent" ref="myQuillEditor" :options="editorOption" @blur="onEditorBlur($event)" @focus="onEditorFocus($event)" @change="onEditorChange($event)" > </quill-editor> <!-- 添加发布和定时发布按钮 v-debounce="3000"设定延时 三秒钟内按下多次只会触发一次事件--> <br> <el-button :disabled="isPublishing" @click="publish" type="primary" v-debounce="3000">发布</el-button> <!-- <hr /> --> <!-- 读取展示 --> <!-- <div class="ql-container ql-snow"> <div class="ql-editor"> {{ conversion }} </div> </div> --> </div> </template> <script> import axios from 'axios' import { quillEditor } from 'vue-quill-editor' // 调用编辑器 import * as Quill from 'quill' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' import 'quill/dist/quill.bubble.css' // 设置字体大小 const fontSizeStyle = Quill.import('attributors/style/size') // 引入这个后会把样式写在style上 fontSizeStyle.whitelist = [ '12px', '14px', '16px', '18px', '20px', '24px', '28px', '32px', '36px' ] Quill.register(fontSizeStyle, true) // 设置字体样式 const Font = Quill.import('attributors/style/font') // 引入这个后会把样式写在style上 const fonts = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong'] Font.whitelist = fonts // 将字体加入到白名单 Quill.register(Font, true) // 工具栏 const toolbarOptions = [ ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线 -----['bold', 'italic', 'underline', 'strike'] [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色-----[{ color: [] }, { background: [] }] [{ align: [] }], // 对齐方式-----[{ align: [] }] [{ size: fontSizeStyle.whitelist }], // 字体大小-----[{ size: ['small', false, 'large', 'huge'] }] [{ font: fonts }], // 字体种类-----[{ font: [] }] [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题 [{ direction: 'ltl' }], // 文本方向-----[{'direction': 'rtl'}] [{ direction: 'rtl' }], // 文本方向-----[{'direction': 'rtl'}] [{ indent: '-1' }, { indent: '+1' }], // 缩进-----[{ indent: '-1' }, { indent: '+1' }] [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表-----[{ list: 'ordered' }, { list: 'bullet' }] [{ script: 'sub' }, { script: 'super' }], // 上标/下标-----[{ script: 'sub' }, { script: 'super' }] ['blockquote', 'code-block'], // 引用 代码块-----['blockquote', 'code-block'] ['clean'], // 清除文本格式-----['clean'] ['link', 'image', 'video'] // 链接、图片、视频-----['link', 'image', 'video'] ] export default { isPublishing: false, // 发布按钮 启用/禁用 name: 'HomeDetails', components: { quillEditor }, data () { return { title: '', // 配置方式二 editorOption: { modules: { toolbar: { container: toolbarOptions, handlers: { image: this.handleImgUpload } } } }, // 配置方式一 // editorOption: { // // 编辑器配置 // placeholder: '请在这里输入', // modules: { // toolbar: [ // ['bold', 'italic', 'underline', 'strike'], // 加粗,斜体,下划线,删除线 // ['blockquote', 'code-block'], // 引用,代码块 // [{ header: 1 }, { header: 2 }], // 标题,键值对的形式;1、2表示字体大小 // [{ list: 'ordered' }, { list: 'bullet' }], // 列表 // [{ script: 'sub' }, { script: 'super' }], // 上下标 // [{ indent: '-1' }, { indent: '+1' }], // 缩进 // // [{ direction: "ltl" }], // 文本方向 // [{ direction: 'rtl' }], // 文本方向 // [{ size: ['small', false, 'large', 'huge'] }], // 字体大小 // [{ header: [1, 2, 3, 4, 5, 6, false] }], // 几级标题 // [{ color: [] }, { background: [] }], // 字体颜色,字体背景颜色 // [{ font: [] }], // 字体 // [{ align: [] }], // 对齐方式 // ['link'], // ["link", "image", "video"], //上传图片、上传视频 // ['clean'] // 清除字体样式 // ] // } // }, editContent: '', // 编辑器内容 conversion: '' // 演示内容 } }, computed: { editor () { return this.$refs.myQuillEditor.quill } }, mounted () { this.$nextTick(() => { this.conversion = this.escapeStringHTML(this.editContent) }) }, methods: { // ========================富文本======================== onEditorReady (editor) { // 准备编辑器 }, onEditorBlur () {}, // 失去焦点事件 onEditorFocus () {}, // 获得焦点事件 // 内容改变事件 onEditorChange () { this.conversion = this.escapeStringHTML(this.editContent) }, // 转码 escapeStringHTML (content) { content = content.replace(/</g, '<') content = content.replace(/>/g, '>') return content } // ========================富文本END======================== } } </script> <style> .ql-editor { min-height: 150px; } .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="SimSun"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimSun"]::before { content: "宋体"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="Microsoft-YaHei"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="Microsoft-YaHei"]::before { content: "微软雅黑"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="KaiTi"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="KaiTi"]::before { content: "楷体"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="FangSong"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="FangSong"]::before { content: "仿宋"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="SimHei"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="SimHei"]::before { content: "黑体"; } .ql-toolbar.ql-snow + .ql-container.ql-snow { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } .ql-toolbar.ql-snow { border-top-left-radius: 5px; border-top-right-radius: 5px; } .ql-snow .ql-stroke, .ql-snow .ql-picker { color: #999; stroke: #999; } .ql-snow .ql-fill, .ql-snow .ql-stroke.ql-fill { fill: #999; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before { content: "12px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before { content: "14px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before { content: "16px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before { content: "20px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before { content: "24px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="36px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="36px"]::before { content: "36px"; } .ql-container { font-size: 14px; } </style> <style lang="scss" scoped> .HomeDetails { padding: 40px 0 0 80px; .quill-editor /deep/ .ql-container { min-height: 490px; } .ql-container { min-height: 500px; } }
public String extract(String str) throws Exception { // 定义正则表达式 String regex = "data:image/png;base64,([^<]+)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(str); String base64ImageData; //用来存放图片预览地址 Map<Integer,String > myMap = new HashMap<Integer,String>(); Integer i = 1; // 提取所有base64编码 pictureVo pictureVo = null; while (matcher.find()) { base64ImageData = matcher.group(1); //解码图片,得到图片预览地址 pictureVo = decode(base64ImageData); //把图片预览地址存起来 myMap.put(i,pictureVo.getPreviewUrl()); System.out.println("打印图片预览地址:==" + myMap.get(i)); i++; //System.out.println("截取:" + matcher.group(1)); } //得到一个html,存入数据库 String html = htmlReplace(str,myMap); // 图片宽度超限 压缩图片 // if (pictureVo.getCompressed()){ // html = html.replaceFirst("<img src", "<img style=\"width: 100%; height: auto;\" src"); // } System.out.println("最终结果:" + html); return html; } /** * //2.解码图片并存放在本地,此图片作为临时文件,上传完毕后删除临时文件 * @param str * @throws Exception */ pictureVo decode( String str) throws Exception { String base64ImageData = str; //将Base64编码的图像数据解码成图片 byte[] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(base64ImageData); ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes); BufferedImage image = ImageIO.read(bis); // 获取图片的宽度和高度 //返回类 pictureVo pictureVo = new pictureVo(); pictureVo.setCompressed(false); int width = image.getWidth(); int height = image.getHeight(); System.out.println("图片尺寸: " + width + "x" + height); bis.close(); //临时图片存放地址 String filePath = null; //将当前环境读取出来 是开发环境还是生产环境 if ("dev".equals(runtimeEnvironment)){ filePath = "/Users/zhouchenghuan/Pictures/"+ UUID.randomUUID().toString()+ ".png"; } else if ("pro".equals(runtimeEnvironment)) { filePath = "/usr/local/java/temp"+ UUID.randomUUID().toString()+ ".png"; } //图片宽度超过800px if (width > 654){ System.out.println("图片宽度超限》》》》》》》》》》》》》》》》》》》》》》》》》"); // 计算缩放后的宽度和高度 int newWidth = 654; int newHeight = (int) ((double) height * newWidth / width); // 创建缩放后的图片 BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = resizedImage.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.drawImage(image, 0, 0, newWidth, newHeight, null); g2d.dispose(); ImageIO.write(resizedImage, "png", new File(filePath)); System.out.println("缩放后的图片已保存到: " + filePath); } else { // 图片宽度未超过800,不需缩放 Files.write(Paths.get(filePath), imageBytes); System.out.println("图片宽度未超过800,无需缩放"); } //上传图片 到 minio 并返回图片预览地址 String uploading = uploading(filePath); pictureVo.setPreviewUrl(uploading); //String previewUrl = ; return pictureVo; } /** * 作用:上传图片至minio,调用此方法返回图片预览地址 * @param filePath * @return * @throws Exception */ String uploading(String filePath) throws Exception { //3.将图片上传至minio //3.1.创建minio链接客户端 FileInputStream fileInputStream = null; fileInputStream = new FileInputStream(filePath); MinioClient minioClient = MinioClient.builder().credentials("你的账号", "密码") .endpoint("http://你的服务器地址").build(); //3.2上传 String objectName = UUID.randomUUID().toString() + ".png"; PutObjectArgs putObjectArgs = PutObjectArgs.builder() .object(objectName)//文件名 .contentType("text/html/png/jpg")//文件类型 .bucket("image")//桶名词 与minio创建的名词一致 .stream(fileInputStream, fileInputStream.available(), -1) //文件流 .build(); minioClient.putObject(putObjectArgs); // 获取文件的下载地址 String downloadUrl = minioClient.getObjectUrl("image", objectName); System.out.println("下载地址: " + downloadUrl); //图片预览地址 String previewUrl = minioClient.presignedGetObject("image", objectName); System.out.println("预览地址: " + previewUrl); //删除临时文件 // 判断文件是否存在 if(Files.exists(Paths.get(filePath))) { try { // 删除文件 Files.delete(Paths.get(filePath)); System.out.println("临时文件删除成功"); } catch (IOException e) { // 异常处理 e.printStackTrace(); } } else { System.out.println("临时文件不存在"); } return previewUrl; } String htmlReplace(String html,Map<Integer,String > myMap){ // 使用正则表达式匹配所有的base64图片并替换成minio的url Pattern pattern = Pattern.compile("data:image/png;base64,([^<]+)"); Matcher matcher = pattern.matcher(html); StringBuffer sb = new StringBuffer(); int i = 1; while (matcher.find()) { matcher.appendReplacement(sb, myMap.get(i) + "\">"); i++; } matcher.appendTail(sb); //把图片编码替换成图片预览url后的html String html2 = sb.toString(); System.out.println(sb.toString()); return html2; }
地址:欢-分享知识和快乐