JavaWeb_(视频网站)_四、博客模块1
添加博客
添加博客流程图
创建博客实体
blog实体中包含了三个复杂字段catagory、subCatagory、tag
blog与catagory属于多对一关系
blog与subCatagory属于多对一关系
subCatagory与tag属于多对多关系
catagory与subCatagory属于一对多关系
blog与tag属于多对多关系
package com.Gary.betobe.domain; import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; //博客 @Entity public class Blog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String coverImage; private String title; @Lob private String content; private String keyword; private Long viewNum; private String createTime; //该博客属于哪一个分类 @ManyToOne(targetEntity = Catagory.class) @JoinColumn(name="catagory_id") private Catagory catagory; //该博客属于哪一个小分类 @ManyToOne(targetEntity = SubCatagory.class) @JoinColumn(name="sub_catagory_id") private SubCatagory subCatagory; //博客标签,多对多 @ManyToMany @JoinTable( name = "blog_tag", joinColumns = @JoinColumn(name="blog_id"), inverseJoinColumns = @JoinColumn(name = "tag_id") ) private Set<Tag> blogTags = new HashSet<Tag>(); //该博客是哪一个人发的 @ManyToOne(targetEntity = User.class) @JoinColumn(name="user_id") private User user; protected Blog() { } public Blog(Long id, String coverImage, String title, String content, String keyword, Long viewNum, String createTime, Catagory catagory, SubCatagory subCatagory, Set<Tag> blogTags) { super(); this.id = id; this.coverImage = coverImage; this.title = title; this.content = content; this.keyword = keyword; this.viewNum = viewNum; this.createTime = createTime; this.catagory = catagory; this.subCatagory = subCatagory; this.blogTags = blogTags; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getCoverImage() { return coverImage; } public void setCoverImage(String coverImage) { this.coverImage = coverImage; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getKeyword() { return keyword; } public void setKeyword(String keyword) { this.keyword = keyword; } public Long getViewNum() { return viewNum; } public void setViewNum(Long viewNum) { this.viewNum = viewNum; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public Catagory getCatagory() { return catagory; } public void setCatagory(Catagory catagory) { this.catagory = catagory; } public SubCatagory getSubCatagory() { return subCatagory; } public void setSubCatagory(SubCatagory subCatagory) { this.subCatagory = subCatagory; } public Set<Tag> getBlogTags() { return blogTags; } public void setBlogTags(Set<Tag> blogTags) { this.blogTags = blogTags; } }
package com.Gary.betobe.domain; import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; //大分类 @Entity public class Catagory { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String catagory; //大分类下的所有博客 @OneToMany(targetEntity = Blog.class) @JoinColumn(name="catagory_id") private Set<Blog> blogs = new HashSet<Blog>(); //该大分类下的所有小分类 @OneToMany(targetEntity = SubCatagory.class) @JoinColumn(name="catagory_id") private Set<SubCatagory> subCatagorys = new HashSet<SubCatagory>(); protected Catagory() { } public Catagory(Long id, String catagory, Set<Blog> blogs, Set<SubCatagory> subCatagorys) { super(); this.id = id; this.catagory = catagory; this.blogs = blogs; this.subCatagorys = subCatagorys; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getCatagory() { return catagory; } public void setCatagory(String catagory) { this.catagory = catagory; } public Set<Blog> getBlogs() { return blogs; } public void setBlogs(Set<Blog> blogs) { this.blogs = blogs; } public Set<SubCatagory> getSubCatagorys() { return subCatagorys; } public void setSubCatagorys(Set<SubCatagory> subCatagorys) { this.subCatagorys = subCatagorys; } }
package com.Gary.betobe.domain; import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; //小分类 @Entity public class SubCatagory { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String subCatagory; //该小分类下的所有博客 @OneToMany(targetEntity = Blog.class) @JoinColumn(name="sub_catagory_id") private Set<Blog> blogs = new HashSet<Blog>(); //这个小分类属于哪一个大分类 @ManyToOne(targetEntity = Catagory.class) @JoinColumn(name="catagory_id") private Catagory catagory; //小分类与标签,多对多 @ManyToMany @JoinTable( name="sub_catagory_tag", joinColumns = @JoinColumn(name = "sub_catagory_id"), inverseJoinColumns = @JoinColumn(name="tag_id") ) private Set<Tag> tags = new HashSet<Tag>(); protected SubCatagory() { } public SubCatagory(Long id, String subCatagory, Set<Blog> blogs, Catagory catagory, Set<Tag> tags) { super(); this.id = id; this.subCatagory = subCatagory; this.blogs = blogs; this.catagory = catagory; this.tags = tags; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getSubCatagory() { return subCatagory; } public void setSubCatagory(String subCatagory) { this.subCatagory = subCatagory; } public Set<Blog> getBlogs() { return blogs; } public void setBlogs(Set<Blog> blogs) { this.blogs = blogs; } public Catagory getCatagory() { return catagory; } public void setCatagory(Catagory catagory) { this.catagory = catagory; } public Set<Tag> getTags() { return tags; } public void setTags(Set<Tag> tags) { this.tags = tags; } }
package com.Gary.betobe.domain; import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToMany; //标签 @Entity public class Tag { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String tag; //该标签下的所有博客 @ManyToMany(mappedBy = "blogTags") private Set<Blog> tagBlogs = new HashSet<Blog>(); //该标签下的所有小分类 @ManyToMany(mappedBy = "tags") private Set<SubCatagory> subCatagoryTage = new HashSet<SubCatagory>(); protected Tag() { } public Tag(Long id, String tag, Set<Blog> tagBlogs, Set<SubCatagory> subCatagoryTage) { super(); this.id = id; this.tag = tag; this.tagBlogs = tagBlogs; this.subCatagoryTage = subCatagoryTage; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTag() { return tag; } public void setTag(String tag) { this.tag = tag; } public Set<Blog> getTagBlogs() { return tagBlogs; } public void setTagBlogs(Set<Blog> tagBlogs) { this.tagBlogs = tagBlogs; } public Set<SubCatagory> getSubCatagoryTage() { return subCatagoryTage; } public void setSubCatagoryTage(Set<SubCatagory> subCatagoryTage) { this.subCatagoryTage = subCatagoryTage; } }
数据库多生成了六张表(六个关系)
给catagory大分类添加一些假数据
给sub_catagory大分类下增加小分类
动态将catagory大分类标签显示在subit-post-blog.html上
<div class="post-category submit-post"> <label>Choose Blog Category: <select> <option th:each="catagory:${catagoryList}" th:text="${catagory.catagory}" th:value="${catagory.catagory}">one</option> </select> </label> </div>
上传Bolg标签的Controller层
@RequestMapping("/submitPostBlog") public String submitPostBlog(Model model) { User user = (User) session.getAttribute("user"); baseDataUtils.getData(model,user.getId().toString()); List<Catagory> catagoryList = catagoryService.findAllCatagory(); System.out.println(catagoryList); model.addAttribute("catagoryList",catagoryList); return "submit-post-blog.html"; }
package com.Gary.betobe.repository; import org.springframework.data.repository.CrudRepository; import com.Gary.betobe.domain.Catagory; public interface CatagoryRepository extends CrudRepository<Catagory,Long>{ }
package com.Gary.betobe.service; import java.util.List; import org.springframework.stereotype.Service; import com.Gary.betobe.domain.Catagory; @Service public interface CatagoryService { List<Catagory> findAllCatagory(); }
接下来制作当改变了Choose Blog Category大标题后,下边的Choose Blog SubCategory下标题也会跟着改变
给大标题和小标题添加一个隐藏button
<!-- 大标题 --> <div class="post-category submit-post"> <label>Choose Blog Category: <select> <option th:each="catagory:${catagoryList}" th:onclick="catagoryClick([[${#setUtils.getSubCatagorys(catagory.subCatagorys)}]],[[${catagory.id}]])" th:value="${catagory.catagory}" th:text="${catagory.catagory}">one</option> </select> </label> <input required="required" id="catagoryIdInput" type="text" style="display:none;"> </div> <!-- 小标题 --> <div class="post-category submit-post"> <label>Choose Blog SubCategory: <select id="subCatagoryId"> <option value="">one</option> <option value="">two</option> <option value="">three</option> </select> </label> <input required="required" id="subcatagoryInInput" type="text" style="display:none"> </div>
<script type="text/javascript"> function catagoryClick(str,id) { //清空select //获得父元素 var subCatagoryId = document.getElementById("subCatagoryId"); //获得父元素下的所有子元素 var childs = subCatagoryId.childNodes; //遍历删除 for(var i = childs.length - 1;i>=0;i--) { subCatagoryId.removeChild(childs[i]); } //切割str var subCatagory = new Array(); subCatagory = str.split("|"); //1,MAD //2,MMD for(var i=0;i<subCatagory.length;i++) { //alert(subCatagory[i]); //2,MMD var idList = new Array(); idList = subCatagory[i].split(","); //alert(idList[1]); //添加option var option = document.createElement("option"); option.innerHTML = idList[1]; //二级下拉点击事件 option.setAttribute("onclick","subCatagoryClick("+idList[0]+")") subCatagoryId.appendChild(option); } // $("#catagoryIdInput").val(id); //alert(str); } function subCatagoryClick(id) { //给subcatagoryinput赋值 $("#subcatagoryInInput").val(id); } </script>
通过Cropper插件更换图片
图片的替换流程图
通过表单提交图片
<form id="uploadBlogCoverImageForm" method="post" enctype="multipart/form-data"> <input type="file" name="file" id="videoUpload" onchange="uploadBlogCover(this)" class="show-for-sr"> </form>
当点击Upload File上传图片按钮后,文件将保存到classpath:static\upload\blog\temp下
上传文件的javascript代码
//上传封面 function uploadBlogCover(e) { //alert(e.files[0].name); var forData = new FormData($("#uploadBlogCoverImageForm")[0]); $.ajax({ type:"POST", cache:false, url:"/uploadImageAJAX", data:forData, processData:false, contentType:false, dataType:"json", success:function(result) { alert("success") }, error:function() { alert("dis success") } }) }
后端处理图片上传请求
@RequestMapping("/uploadImageAJAX") @ResponseBody public String uploadImageAJAX(@RequestParam("file")MultipartFile file) throws Exception { //保存图片 //创建文件 String path = ResourceUtils.getURL("classpath:").getPath()+"static/upload/blog/temp"; String name = file.getOriginalFilename(); File dest = new File(path + "/" +name); //如果路径不存在,创建路径 if(!dest.getParentFile().exists()) { dest.getParentFile().mkdir(); } //保存文件 file.transferTo(dest); String json = "{\"success\":"+true+"}"; return json; }
当图片成功上传到classpath:static\upload\blog\temp后,在ajax中使用cropperMy.replace()将读取图片上传到本地文件夹的位置
cropperMy.replace("http://www.pinzhi365.com/upload/blog/temp/"+fileName,false);
//上传封面 function uploadBlogCover(e) { //alert(e.files[0].name); var fileName = e.files[0].name; var forData = new FormData($("#uploadBlogCoverImageForm")[0]); $.ajax({ type:"POST", cache:false, url:"/uploadImageAJAX", data:forData, processData:false, contentType:false, dataType:"json", success:function(result) { cropperMy.replace("http://www.pinzhi365.com/upload/blog/temp/"+fileName,false); }, error:function() { alert("dis success") } }) }
如何将前端切割好的图片保存分析
Ajax上传Base64格式文件前端书写
<a href="javascript;void(0);" onclick="saveImage()" style="background: #656fc3;border-bottom: 3px solid #424da9" class="button"> <i class="fa fa-plus"></i> Save COVER </a>
//保存切割之后的图片 function saveImage() { //alert("Gary555"); //拿到Base64格式的文本 var base64URL = cropperMy.getCroppedCanvas({width:770,height:370}).toDataURL("image/jpeg"); //ajax保存图片 $.post( [[@{~/uploadCoverAJAX}]], {"base64":base64URL}, function(data) { if(data.success) { $("#coverImageInput").val("blog/cover/"+data.fileName); layer.msg("上传成功!!") } //alert(); //文件路径 }, "json" ) }
后端处理上传的Base64文件图片
@RequestMapping("/uploadCoverAJAX") @ResponseBody public String uploadCoverAJAX(String base64) throws Exception { //获得classpath在本地的地址 String path = ResourceUtils.getURL("classpath:").getPath() + "static/upload/blog/cover"; //保存图片 File file = new File(path); if(!file.exists()) { file.mkdir(); } //替换数据 if(base64.indexOf("jpeg")!=-1) { base64 = base64.replaceFirst("jpeg", "jpg"); } //获取文件名 String upName = UUID.randomUUID().toString()+System.currentTimeMillis()+"."+base64.substring(11,14); //将base64中有用的数据保存下来 String iconBase64 = base64.substring(22); //将base64换位字节数据 byte[] buffer = Base64Coder.decode(iconBase64); //用FileOutputStream写文件 FileOutputStream out = new FileOutputStream(path + "/" + upName); out.write(buffer); out.close(); //返回Json String json = "{\"success\":"+true+",\"fileName\":\""+upName+"\"}"; return json; }
前端封装富文本字段
<div class="large-12 columns submit-post"> <button class="button expanded" type="button" onclick="mySubmit()">publish now</button> </div>
富文本表单字段的提交
//自己的表单提交 function mySubmit() { var markup = $(".summernote").summernote('code'); //富文本的内容赋值到textarea中 $("#contentTextarea").text(markup); //表单提交 $("#submitButton").click(); }
<form th:action="@{~/saveBlog}" method="post" data-abide novalidate> <div data-abide-error class="alert callout submit-post" style="display: none;"> <p><i class="fa fa-exclamation-triangle"></i> There are some errors in your form.</p> </div> <div class="row"> <div class="large-12 columns submit-post"> <div class="upload-video"> <label for="videoUpload" class="button">Upload File</label> <span>No file chosen</span> </div> <p class="extraMargin">Please upload the appropriate blog cover recommendation 770 * 370.</p> <!-- 图片切割 --> <div style="width:400px;heigh:280px;"> <img id="image" src="../upload/user/head/1.jpg"> </div> <div> </div> <h6>Perview Cover</h6> <div class="blogCover" style="overflow:hidden;height:770px;width:370px;position:relative;"></div> <div> </div> <a href="javascript:void(0);" onclick="saveImage()" style="background: #656fc3;border-bottom: 3px solid #424da9" class="button"> <i class="fa fa-plus"></i> Save COVER </a> </div> <div class="large-12 columns"> <div class="post-meta submit-post"> <label>Meta Title: <textarea name="title" required="required" placeholder="enter meta title"></textarea> </label> <p>IF you want to put your custom meta Title then put here otherwise your post title will be the default meta Title</p> </div> <div class="post-meta"> <label>Meta Description: </label> <!-- 富文本 --> <div class="summernote"></div> <textarea id="contentTextarea" name="content" style="display:none;"></textarea> <div class="submit-post"> <p>IF you want to put your custom meta description then put here otherwise your post description will be the default meta description</p> </div> </div> <div class="post-meta submit-post"> <label>Meta keywords: <textarea name="keyword" required="required" placeholder="enter meta keywords"></textarea> </label> <p>IF you want to put your custom meta Keywords then put here otherwise your post Keywords will be the default meta Keywords</p> </div> <!-- 大标题 --> <div class="post-category submit-post"> <label>Choose Blog Category: <select> <option th:each="catagory:${catagoryList}" th:onclick="catagoryClick([[${#setUtils.getSubCatagorys(catagory.subCatagorys)}]],[[${catagory.id}]])" th:value="${catagory.catagory}" th:text="${catagory.catagory}">one</option> </select> </label> <input required="required" name="catagoryId" id="catagoryIdInput" type="text" style="display:none;"> </div> <!-- 小标题 --> <div class="post-category submit-post"> <label>Choose Blog SubCategory: <select id="subCatagoryId"> <option value="">one</option> <option value="">two</option> <option value="">three</option> </select> </label> <input required="required" name="subCatagoryId" id="subcatagoryInInput" type="text" style="display:none"> </div> </div> <div class="large-12 columns submit-post"> <label>Tags: <!-- 英文逗号隔开 --> <input name="tagsinput" id="tagsinputval" class="tagsinput" data-role="tagsinput" value="faltui,这是一个标签" placeholder="输入后回车"/> </label> </div> <input id="coverImageInput" name="coverImage" type="text" style="display:none;"> <div class="large-12 columns submit-post"> <button id="submitButton" type="submit" style="display:none;"></button> <button class="button expanded" type="button" onclick="mySubmit()">publish now</button> </div> </div> </form>
小分类与标签绑定关系
更新更新SubCatagory小标签
展示上传图片(期间出了一个bug,栈溢出问题 解决:传送门)
BlogController.java下的saveBlog请求
@RequestMapping("/saveBlog") public String saveBlog(Blog blog,String tagsinput,String catagoryId,String subCatagoryId) { System.err.println("blog = "+blog); //ViewNum //createTime //catagory System.err.println("catagoryId = "+catagoryId); //subCatagory System.err.println("subCatagoryId = "+subCatagoryId); //user session //blogTags System.err.println("tagsinput = "+tagsinput); //封装分类 Catagory catagory = catagoryService.findCatagoryById(catagoryId); blog.setCatagory(catagory); //封装小分类 SubCatagory subCatagory = subCatagoryService.findSubCatagoryById(subCatagoryId); //blog.setSubCatagory(subCatagory); //封装创建时间 Date date = new Date(System.currentTimeMillis()); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm"); String createTime = format.format(date); blog.setCreateTime(createTime); //封装标签 //tagsinput = tagsinput.toUpperCase(); String[] tags = tagsinput.split(","); Set<Tag> blogTags = new HashSet<>(); for(int i=0;i<tags.length;i++) { Tag tag = null; //如果标签不存在,数据库里没有重复的标签 if(tagService.findTagByTag(tags[i]) ==null ) { //如果没有重复的,可以添加 tag = new Tag(null,tags[i],new HashSet<>(),new HashSet<>()); tag = tagService.saveTag(tag); } //如果标签存在 else { //不可添加 tag = tagService.findTagByTag(tags[i]); } blogTags.add(tag); //维护subCatagory与tag之间多对多关系 subCatagory.getTags().add(tag); System.out.println("111"); tag.getSubCatagoryTage().add(subCatagory); } //维护blog与tag关系 blog.setBlogTags(blogTags); blog.setSubCatagory(subCatagory); //封装发布博客的用户 User user = (User) session.getAttribute("user"); blog.setUser(user); //封装浏览数目 blog.setViewNum(0L); //保存 blogService.saveBlog(blog); return "redirect:/index"; }