├── src ├── main │ ├── resources │ │ ├── templates │ │ │ ├── themes │ │ │ │ ├── README │ │ │ │ └── default │ │ │ │ │ ├── page.html │ │ │ │ │ ├── links.html │ │ │ │ │ ├── archives.html │ │ │ │ │ ├── post.html │ │ │ │ │ ├── index.html │ │ │ │ │ ├── page-category.html │ │ │ │ │ └── header.html │ │ │ ├── admin │ │ │ │ ├── footer.html │ │ │ │ ├── page_list.html │ │ │ │ └── article_list.html │ │ │ └── comm │ │ │ │ ├── error_404.html │ │ │ │ ├── error_500.html │ │ │ │ ├── macros.html │ │ │ │ └── tale_comment.html │ │ ├── static │ │ │ ├── user │ │ │ │ └── img │ │ │ │ │ ├── logo.png │ │ │ │ │ ├── bg-ico.png │ │ │ │ │ ├── favicon.png │ │ │ │ │ ├── rand │ │ │ │ │ ├── 1.jpg │ │ │ │ │ ├── 10.jpg │ │ │ │ │ ├── 11.jpg │ │ │ │ │ ├── 12.jpg │ │ │ │ │ ├── 13.jpg │ │ │ │ │ ├── 14.jpg │ │ │ │ │ ├── 15.jpg │ │ │ │ │ ├── 16.jpg │ │ │ │ │ ├── 17.jpg │ │ │ │ │ ├── 18.jpg │ │ │ │ │ ├── 19.jpg │ │ │ │ │ ├── 2.jpg │ │ │ │ │ ├── 3.jpg │ │ │ │ │ ├── 4.jpg │ │ │ │ │ ├── 5.jpg │ │ │ │ │ ├── 6.jpg │ │ │ │ │ ├── 7.jpg │ │ │ │ │ ├── 8.jpg │ │ │ │ │ └── 9.jpg │ │ │ │ │ └── apple-touch-icon.png │ │ │ └── admin │ │ │ │ ├── images │ │ │ │ ├── bg │ │ │ │ │ ├── 1.png │ │ │ │ │ ├── 2.png │ │ │ │ │ ├── 3.png │ │ │ │ │ ├── 4.png │ │ │ │ │ └── 5.png │ │ │ │ ├── logo.png │ │ │ │ ├── attach.png │ │ │ │ ├── favicon.png │ │ │ │ ├── loading.gif │ │ │ │ ├── small │ │ │ │ │ └── bg.jpg │ │ │ │ └── d01b0bff0feff9d8725b8de4145c222e.jpg │ │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ │ ├── plugins │ │ │ │ ├── md │ │ │ │ │ ├── img │ │ │ │ │ │ └── editor.png │ │ │ │ │ └── js │ │ │ │ │ │ └── jquery.scrollto.js │ │ │ │ ├── select2.dist.css │ │ │ │ │ ├── select2.png │ │ │ │ │ ├── select2x2.png │ │ │ │ │ ├── select2-spinner.gif │ │ │ │ │ └── select2-bootstrap.css │ │ │ │ ├── jquery-multi-select │ │ │ │ │ ├── img │ │ │ │ │ │ └── switch.png │ │ │ │ │ └── jquery.quicksearch.js │ │ │ │ └── tagsinput │ │ │ │ │ └── jquery.tagsinput.css │ │ │ │ ├── js │ │ │ │ ├── messages_zh.min.js │ │ │ │ ├── toggles.min.js │ │ │ │ ├── article.js │ │ │ │ ├── html5.min.js │ │ │ │ ├── install.js │ │ │ │ ├── respond.min.js │ │ │ │ └── base.js │ │ │ │ └── css │ │ │ │ ├── xcode.min.css │ │ │ │ └── multi-select.css │ │ ├── application-jdbc.properties │ │ ├── application.properties │ │ ├── banner.txt │ │ └── log4j2.xml │ └── java │ │ └── com │ │ └── my │ │ └── blog │ │ └── website │ │ ├── dto │ │ ├── ErrorCode.java │ │ ├── MetaDto.java │ │ ├── LogActions.java │ │ ├── Types.java │ │ └── DataSource.java │ │ ├── utils │ │ ├── backup │ │ │ ├── ColumnCollection.java │ │ │ ├── FKCollection.java │ │ │ ├── Column.java │ │ │ ├── FK.java │ │ │ ├── TableCollection.java │ │ │ ├── db │ │ │ │ ├── ColumnCollection.java │ │ │ │ ├── Row.java │ │ │ │ ├── Column.java │ │ │ │ └── DataTable.java │ │ │ └── Table.java │ │ ├── GsonUtils.java │ │ ├── AdminCommons.java │ │ ├── LogAspect.java │ │ ├── IPKit.java │ │ ├── ZipUtils.java │ │ ├── Tools.java │ │ └── MapCache.java │ │ ├── exception │ │ └── TipException.java │ │ ├── service │ │ ├── IOptionService.java │ │ ├── ILogService.java │ │ ├── IUserService.java │ │ ├── IAttachService.java │ │ ├── IRelationshipService.java │ │ ├── ICommentService.java │ │ ├── ISiteService.java │ │ ├── IMetaService.java │ │ ├── impl │ │ │ ├── OptionServiceImpl.java │ │ │ ├── LogServiceImpl.java │ │ │ ├── AttachServiceImpl.java │ │ │ ├── RelationshipServiceImpl.java │ │ │ └── UserServiceImpl.java │ │ └── IContentService.java │ │ ├── modal │ │ ├── Vo │ │ │ ├── RelationshipVoKey.java │ │ │ ├── OptionVo.java │ │ │ ├── AttachVo.java │ │ │ ├── LogVo.java │ │ │ ├── MetaVo.java │ │ │ ├── UserVo.java │ │ │ ├── CommentVo.java │ │ │ └── ContentVo.java │ │ └── Bo │ │ │ ├── BackResponseBo.java │ │ │ ├── ArchiveBo.java │ │ │ ├── CommentBo.java │ │ │ ├── StatisticsBo.java │ │ │ └── RestResponseBo.java │ │ ├── dao │ │ ├── RelationshipVoMapper.java │ │ ├── LogVoMapper.java │ │ ├── UserVoMapper.java │ │ ├── AttachVoMapper.java │ │ ├── OptionVoMapper.java │ │ ├── MetaVoMapper.java │ │ ├── CommentVoMapper.java │ │ └── ContentVoMapper.java │ │ ├── controller │ │ ├── GlobalExceptionHandler.java │ │ ├── BaseController.java │ │ └── admin │ │ │ ├── CategoryController.java │ │ │ ├── LinksController.java │ │ │ ├── AuthController.java │ │ │ └── SettingController.java │ │ ├── interceptor │ │ ├── WebMvcConfig.java │ │ └── BaseInterceptor.java │ │ ├── constant │ │ └── WebConst.java │ │ └── CoreApplication.java └── test │ └── java │ └── com │ └── my │ └── blog │ └── website │ ├── Pwdtest.java │ ├── TranscationTest.java │ ├── controller │ └── IndexControllerTest.java │ └── AsyncTest.java ├── 开题参考.docx ├── screenshot ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png └── 8.png ├── 个人博客系统的设计与实现.doc ├── upload ├── 2019 │ └── 09 │ │ └── u94gh751dmhofo50gj8ivab60s.png └── 2024 │ └── 01 │ └── 6b543ive5ohtfps7cgu4q318ql.jpg ├── .gitignore └── README.md /src/main/resources/templates/themes/README: -------------------------------------------------------------------------------- 1 | 这里存放主题 -------------------------------------------------------------------------------- /开题参考.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/开题参考.docx -------------------------------------------------------------------------------- /screenshot/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/1.png -------------------------------------------------------------------------------- /screenshot/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/2.png -------------------------------------------------------------------------------- /screenshot/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/3.png -------------------------------------------------------------------------------- /screenshot/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/4.png -------------------------------------------------------------------------------- /screenshot/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/5.png -------------------------------------------------------------------------------- /screenshot/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/6.png -------------------------------------------------------------------------------- /screenshot/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/7.png -------------------------------------------------------------------------------- /screenshot/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/screenshot/8.png -------------------------------------------------------------------------------- /个人博客系统的设计与实现.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/个人博客系统的设计与实现.doc -------------------------------------------------------------------------------- /src/main/resources/static/user/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/logo.png -------------------------------------------------------------------------------- /src/main/resources/static/user/img/bg-ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/bg-ico.png -------------------------------------------------------------------------------- /src/main/resources/static/user/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/favicon.png -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/1.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/10.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/11.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/12.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/13.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/14.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/15.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/16.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/17.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/18.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/19.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/2.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/3.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/4.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/5.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/6.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/7.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/8.jpg -------------------------------------------------------------------------------- /src/main/resources/static/user/img/rand/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/rand/9.jpg -------------------------------------------------------------------------------- /upload/2019/09/u94gh751dmhofo50gj8ivab60s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/upload/2019/09/u94gh751dmhofo50gj8ivab60s.png -------------------------------------------------------------------------------- /upload/2024/01/6b543ive5ohtfps7cgu4q318ql.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/upload/2024/01/6b543ive5ohtfps7cgu4q318ql.jpg -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/bg/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/bg/1.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/bg/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/bg/2.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/bg/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/bg/3.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/bg/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/bg/4.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/bg/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/bg/5.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/logo.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/attach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/attach.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/favicon.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/loading.gif -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/small/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/small/bg.jpg -------------------------------------------------------------------------------- /src/main/resources/static/admin/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/main/resources/static/user/img/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/user/img/apple-touch-icon.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/md/img/editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/plugins/md/img/editor.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/main/resources/static/admin/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/main/resources/static/admin/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/main/resources/static/admin/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/select2.dist.css/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/plugins/select2.dist.css/select2.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/select2.dist.css/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/plugins/select2.dist.css/select2x2.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/images/d01b0bff0feff9d8725b8de4145c222e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/images/d01b0bff0feff9d8725b8de4145c222e.jpg -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/jquery-multi-select/img/switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/plugins/jquery-multi-select/img/switch.png -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/select2.dist.css/select2-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuLin-Coder/No221PersonalBlogManagementSystem/HEAD/src/main/resources/static/admin/plugins/select2.dist.css/select2-spinner.gif -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dto/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dto; 2 | 3 | /** 4 | * 错误提示 5 | * Created by 13 on 2017/2/26. 6 | */ 7 | public interface ErrorCode { 8 | 9 | /** 10 | * 非法请求 11 | */ 12 | String BAD_REQUEST = "BAD REQUEST"; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/ColumnCollection.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class ColumnCollection extends ArrayList{ 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = -4983492395879238027L; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dto/MetaDto.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dto; 2 | 3 | import com.my.blog.website.modal.Vo.MetaVo; 4 | 5 | public class MetaDto extends MetaVo { 6 | 7 | private int count; 8 | 9 | public int getCount() { 10 | return count; 11 | } 12 | 13 | public void setCount(int count) { 14 | this.count = count; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/GsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | import com.google.gson.Gson; 4 | 5 | /** 6 | * json转换工具 7 | * Created by Administrator on 2017/3/13 013. 8 | */ 9 | public class GsonUtils { 10 | 11 | private static final Gson gson = new Gson(); 12 | 13 | public static String toJsonString(Object object){ 14 | return object==null?null:gson.toJson(object); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/exception/TipException.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.exception; 2 | 3 | public class TipException extends RuntimeException { 4 | 5 | public TipException() { 6 | } 7 | 8 | public TipException(String message) { 9 | super(message); 10 | } 11 | 12 | public TipException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | 16 | public TipException(Throwable cause) { 17 | super(cause); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/FKCollection.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class FKCollection extends ArrayList{ 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = -972085209611643212L; 11 | 12 | public boolean isReferenced(Table referenceTable){ 13 | for(FK fk : this){ 14 | if(fk.getReferenceTable().equals(referenceTable)){ 15 | return true; 16 | } 17 | } 18 | return false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/application-jdbc.properties: -------------------------------------------------------------------------------- 1 | # db config 2 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource 3 | spring.datasource.driverClassName=com.mysql.jdbc.Driver 4 | spring.datasource.url=jdbc:mysql://localhost:3306/no221_tale?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true 5 | spring.datasource.username=root 6 | spring.datasource.password=123456 7 | spring.datasource.initialSize=20 8 | spring.datasource.minIdle=10 9 | spring.datasource.maxActive=100 10 | -------------------------------------------------------------------------------- /src/test/java/com/my/blog/website/Pwdtest.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website; 2 | 3 | import com.my.blog.website.modal.Vo.UserVo; 4 | import com.my.blog.website.utils.TaleUtils; 5 | 6 | /** 7 | * Created by shuaihan on 2017/4/2. 8 | */ 9 | public class Pwdtest { 10 | public static void main(String args[]){ 11 | UserVo user = new UserVo(); 12 | user.setUsername("admin"); 13 | user.setPassword("asdfasdfs"); 14 | String encodePwd = TaleUtils.MD5encode(user.getUsername() + user.getPassword()); 15 | System.out.println(encodePwd); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/messages_zh.min.js: -------------------------------------------------------------------------------- 1 | $.extend($.validator.messages,{required:"这是必填字段",remote:"请修正此字段",email:"请输入有效的电子邮件地址",url:"请输入有效的网址",date:"请输入有效的日期",dateISO:"请输入有效的日期 (YYYY-MM-DD)",number:"请输入有效的数字",digits:"只能输入数字",creditcard:"请输入有效的信用卡号码",equalTo:"你的输入不相同",extension:"请输入有效的后缀",maxlength:$.validator.format("最多可以输入 {0} 个字符"),minlength:$.validator.format("最少要输入 {0} 个字符"),rangelength:$.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"),range:$.validator.format("请输入范围在 {0} 到 {1} 之间的数值"),max:$.validator.format("请输入不大于 {0} 的数值"),min:$.validator.format("请输入不小于 {0} 的数值")}); 2 | //# sourceMappingURL=messages_zh.min.js.map -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/IOptionService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.my.blog.website.modal.Vo.OptionVo; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * options的接口 10 | * Created by BlueT on 2017/3/7. 11 | */ 12 | public interface IOptionService { 13 | 14 | void insertOption(OptionVo optionVo); 15 | 16 | void insertOption(String name, String value); 17 | 18 | List getOptions(); 19 | 20 | 21 | /** 22 | * 保存一组配置 23 | * 24 | * @param options 25 | */ 26 | void saveOptions(Map options); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dto/LogActions.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dto; 2 | 3 | /** 4 | * 日志表的action字段 5 | * Created by BlueT on 2017/3/4. 6 | */ 7 | public enum LogActions { 8 | 9 | LOGIN("登录后台"), UP_PWD("修改密码"), UP_INFO("修改个人信息"), 10 | DEL_ARTICLE("删除文章"), DEL_PAGE("删除页面"), SYS_BACKUP("系统备份"), 11 | SYS_SETTING("保存系统设置"), INIT_SITE("初始化站点"); 12 | 13 | private String action; 14 | 15 | public String getAction() { 16 | return action; 17 | } 18 | 19 | public void setAction(String action) { 20 | this.action = action; 21 | } 22 | 23 | LogActions(String action) { 24 | this.action = action; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 2019 © Blog
6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=jdbc 2 | 3 | # thymeleaf 4 | spring.thymeleaf.prefix=classpath:/templates/ 5 | spring.thymeleaf.check-template-location=true 6 | spring.thymeleaf.suffix=.html 7 | spring.thymeleaf.encoding=UTF-8 8 | spring.thymeleaf.content-type=text/html 9 | spring.thymeleaf.mode=HTML5 10 | spring.thymeleaf.cache=false 11 | 12 | mybatis.mapper-locations=classpath:mapper/*.xml 13 | mybatis.type-aliases-package=com.my.blog.website.dao 14 | 15 | server.port=8080 16 | 17 | #pagehelper 18 | pagehelper.helperDialect=mysql 19 | pagehelper.reasonable=true 20 | pagehelper.support-methods-arguments=true 21 | pagehelper.params=count=countSql 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/Column.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup; 2 | 3 | public class Column { 4 | private String name; 5 | private String typeName; 6 | private int dataType; 7 | 8 | public String getName() { 9 | return name; 10 | } 11 | 12 | public int getDataType() { 13 | return dataType; 14 | } 15 | 16 | public Column(String name, String typeName, int dataType) { 17 | super(); 18 | this.name = name; 19 | this.typeName = typeName; 20 | this.dataType = dataType; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return "Column [name=" + name + ", typeName=" + typeName 26 | + ", dataType=" + dataType + "]"; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/FK.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup; 2 | 3 | public class FK { 4 | private String column; 5 | private Table referenceTable; 6 | private String referencePK; 7 | 8 | public Table getReferenceTable() { 9 | return referenceTable; 10 | } 11 | 12 | public FK(String column, Table referenceTable, String referencePK) { 13 | this.column = column; 14 | this.referenceTable = referenceTable; 15 | this.referencePK = referencePK; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return "FK [column=" + column + ", referenceTable=" + referenceTable 21 | + ", referencePK=" + referencePK + "]"; 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/RelationshipVoKey.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class RelationshipVoKey implements Serializable { 9 | /** 10 | * 内容主键 11 | */ 12 | private Integer cid; 13 | 14 | /** 15 | * 项目主键 16 | */ 17 | private Integer mid; 18 | 19 | private static final long serialVersionUID = 1L; 20 | 21 | public Integer getCid() { 22 | return cid; 23 | } 24 | 25 | public void setCid(Integer cid) { 26 | this.cid = cid; 27 | } 28 | 29 | public Integer getMid() { 30 | return mid; 31 | } 32 | 33 | public void setMid(Integer mid) { 34 | this.mid = mid; 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/TableCollection.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class TableCollection extends ArrayList { 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = -5824322959198795936L; 11 | 12 | /** 13 | * Sort tables according to constraints 14 | */ 15 | public void sort(){ 16 | for(int i = 0 ; i < size(); ){ 17 | boolean corrupted = false; 18 | for(int j = i + 1; j < size(); j++){ 19 | if(get(i).isReferenced(get(j))){ 20 | Table table = get(i); 21 | remove(table); 22 | add(table); 23 | corrupted = true; 24 | break; 25 | } 26 | } 27 | if(!corrupted){ 28 | i++; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/ILogService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.my.blog.website.modal.Vo.LogVo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by BlueT on 2017/3/4. 9 | */ 10 | public interface ILogService { 11 | 12 | /** 13 | * 保存操作日志 14 | * 15 | * @param logVo 16 | */ 17 | void insertLog(LogVo logVo); 18 | 19 | /** 20 | * 保存 21 | * @param action 22 | * @param data 23 | * @param ip 24 | * @param authorId 25 | */ 26 | void insertLog(String action, String data, String ip, Integer authorId); 27 | 28 | /** 29 | * 获取日志分页 30 | * @param page 当前页 31 | * @param limit 每页条数 32 | * @return 日志 33 | */ 34 | List getLogs(int page,int limit); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/db/ColumnCollection.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup.db; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class ColumnCollection extends ArrayList{ 6 | 7 | private static final long serialVersionUID = -3399188477563370223L; 8 | 9 | public int indexByLabel(String label){ 10 | for(int i = 0; i < this.size(); i++){ 11 | if(get(i).getLabel().equals(label)){ 12 | return i; 13 | } 14 | } 15 | return -1; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | if(size() == 0){ 21 | return "Columns is empty"; 22 | } 23 | String s = "Columns : {" + String.valueOf(get(0).getLabel()); 24 | for(int i = 1; i < size(); i++){ 25 | s += ", " + String.valueOf(get(i).getLabel()); 26 | } 27 | s += "}"; 28 | return s; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/static/admin/css/xcode.min.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#fff;color:black}.hljs-comment,.hljs-quote{color:#006a00}.hljs-keyword,.hljs-selector-tag,.hljs-literal{color:#aa0d91}.hljs-name{color:#008}.hljs-variable,.hljs-template-variable{color:#660}.hljs-string{color:#c41a16}.hljs-regexp,.hljs-link{color:#080}.hljs-title,.hljs-tag,.hljs-symbol,.hljs-bullet,.hljs-number,.hljs-meta{color:#1c00cf}.hljs-section,.hljs-class .hljs-title,.hljs-type,.hljs-attr,.hljs-built_in,.hljs-builtin-name,.hljs-params{color:#5c2699}.hljs-attribute,.hljs-subst{color:#000}.hljs-formula{background-color:#eee;font-style:italic}.hljs-addition{background-color:#baeeba}.hljs-deletion{background-color:#ffc8bd}.hljs-selector-id,.hljs-selector-class{color:#9b703f}.hljs-doctag,.hljs-strong{font-weight:bold}.hljs-emphasis{font-style:italic} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | # Build Tools 3 | 4 | .gradle 5 | /build/ 6 | !gradle/wrapper/gradle-wrapper.jar 7 | 8 | target/ 9 | !.mvn/wrapper/maven-wrapper.jar 10 | 11 | out/ 12 | 13 | ###################################################################### 14 | # IDE 15 | 16 | ### STS ### 17 | .apt_generated 18 | .classpath 19 | .factorypath 20 | .project 21 | .settings 22 | .springBeans 23 | 24 | ### IntelliJ IDEA ### 25 | .idea 26 | *.iws 27 | *.iml 28 | *.ipr 29 | 30 | ### NetBeans ### 31 | nbproject/private/ 32 | build/* 33 | nbbuild/ 34 | dist/ 35 | nbdist/ 36 | .nb-gradle/ 37 | 38 | ###################################################################### 39 | # Others 40 | *.log 41 | *.xml.versionsBackup 42 | *.swp 43 | 44 | !*/build/*.java 45 | !*/build/*.html 46 | !*/build/*.xml 47 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/Table.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup; 2 | 3 | 4 | public class Table { 5 | private String name; 6 | private ColumnCollection columns; 7 | private FKCollection constraints; 8 | 9 | public String getName() { 10 | return name; 11 | } 12 | 13 | public Table(String name) { 14 | this.name = name; 15 | this.columns = new ColumnCollection(); 16 | this.constraints = new FKCollection(); 17 | } 18 | 19 | public ColumnCollection getColumns() { 20 | return columns; 21 | } 22 | 23 | public FKCollection getConstraints() { 24 | return constraints; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "Table [name=" + name + "]"; 30 | } 31 | 32 | public boolean isReferenced(Table referenceTable){ 33 | return constraints.isReferenced(referenceTable); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/IUserService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.my.blog.website.modal.Vo.UserVo; 4 | 5 | /** 6 | * Created by BlueT on 2017/3/3. 7 | */ 8 | public interface IUserService { 9 | 10 | /** 11 | * 保存用户数据 12 | * 13 | * @param userVo 用户数据 14 | * @return 主键 15 | */ 16 | 17 | Integer insertUser(UserVo userVo); 18 | 19 | /** 20 | * 通过uid查找对象 21 | * @param uid 22 | * @return 23 | */ 24 | UserVo queryUserById(Integer uid); 25 | 26 | /** 27 | * 用戶登录 28 | * @param username 29 | * @param password 30 | * @return 31 | */ 32 | UserVo login(String username, String password); 33 | 34 | /** 35 | * 根据主键更新user对象 36 | * @param userVo 37 | * @return 38 | */ 39 | void updateByUid(UserVo userVo); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |

8 |
9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 | 17 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dto/Types.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dto; 2 | 3 | public enum Types { 4 | TAG("tag"), 5 | CATEGORY("category"), 6 | ARTICLE("post"), 7 | PUBLISH("publish"), 8 | PAGE("page"), 9 | DRAFT("draft"), 10 | LINK("link"), 11 | IMAGE("image"), 12 | FILE("file"), 13 | CSRF_TOKEN("csrf_token"), 14 | COMMENTS_FREQUENCY("comments:frequency"), 15 | 16 | /** 17 | * 附件存放的URL,默认为网站地址,如集成第三方则为第三方CDN域名 18 | */ 19 | ATTACH_URL("attach_url"), 20 | 21 | /** 22 | * 网站要过滤,禁止访问的ip列表 23 | */ 24 | BLOCK_IPS("site_block_ips"); 25 | 26 | 27 | private String type; 28 | 29 | public java.lang.String getType() { 30 | return type; 31 | } 32 | 33 | public void setType(java.lang.String type) { 34 | this.type = type; 35 | } 36 | 37 | Types(java.lang.String type) { 38 | this.type = type; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Bo/BackResponseBo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Bo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by 13 on 2017/2/25. 7 | */ 8 | public class BackResponseBo implements Serializable { 9 | 10 | private String attachPath; 11 | private String themePath; 12 | private String sqlPath; 13 | 14 | public String getAttachPath() { 15 | return attachPath; 16 | } 17 | 18 | public void setAttachPath(String attachPath) { 19 | this.attachPath = attachPath; 20 | } 21 | 22 | public String getThemePath() { 23 | return themePath; 24 | } 25 | 26 | public void setThemePath(String themePath) { 27 | this.themePath = themePath; 28 | } 29 | 30 | public String getSqlPath() { 31 | return sqlPath; 32 | } 33 | 34 | public void setSqlPath(String sqlPath) { 35 | this.sqlPath = sqlPath; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/IAttachService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.my.blog.website.modal.Vo.AttachVo; 5 | 6 | /** 7 | * Created by wangq on 2017/3/20. 8 | */ 9 | public interface IAttachService { 10 | /** 11 | * 分页查询附件 12 | * @param page 13 | * @param limit 14 | * @return 15 | */ 16 | PageInfo getAttachs(Integer page,Integer limit); 17 | 18 | /** 19 | * 保存附件 20 | * 21 | * @param fname 22 | * @param fkey 23 | * @param ftype 24 | * @param author 25 | */ 26 | void save(String fname, String fkey, String ftype, Integer author); 27 | 28 | /** 29 | * 根据附件id查询附件 30 | * @param id 31 | * @return 32 | */ 33 | AttachVo selectById(Integer id); 34 | 35 | /** 36 | * 删除附件 37 | * @param id 38 | */ 39 | void deleteById(Integer id); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/IRelationshipService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.my.blog.website.modal.Vo.RelationshipVoKey; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by BlueT on 2017/3/18. 9 | */ 10 | public interface IRelationshipService { 11 | /** 12 | * 按住键删除 13 | * @param cid 14 | * @param mid 15 | */ 16 | void deleteById(Integer cid, Integer mid); 17 | 18 | /** 19 | * 按主键统计条数 20 | * @param cid 21 | * @param mid 22 | * @return 条数 23 | */ 24 | Long countById(Integer cid, Integer mid); 25 | 26 | 27 | /** 28 | * 保存對象 29 | * @param relationshipVoKey 30 | */ 31 | void insertVo(RelationshipVoKey relationshipVoKey); 32 | 33 | /** 34 | * 根据id搜索 35 | * @param cid 36 | * @param mid 37 | * @return 38 | */ 39 | List getRelationshipById(Integer cid, Integer mid); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/OptionVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class OptionVo implements Serializable { 9 | /** 10 | * 配置名称 11 | */ 12 | private String name; 13 | 14 | /** 15 | * 配置值 16 | */ 17 | private String value; 18 | 19 | private String description; 20 | 21 | private static final long serialVersionUID = 1L; 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public void setName(String name) { 28 | this.name = name; 29 | } 30 | 31 | public String getValue() { 32 | return value; 33 | } 34 | 35 | public void setValue(String value) { 36 | this.value = value; 37 | } 38 | 39 | public String getDescription() { 40 | return description; 41 | } 42 | 43 | public void setDescription(String description) { 44 | this.description = description; 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/RelationshipVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Vo.RelationshipVoExample; 4 | import com.my.blog.website.modal.Vo.RelationshipVoKey; 5 | 6 | import java.util.List; 7 | import org.apache.ibatis.annotations.Param; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public interface RelationshipVoMapper { 12 | long countByExample(RelationshipVoExample example); 13 | 14 | int deleteByExample(RelationshipVoExample example); 15 | 16 | int deleteByPrimaryKey(RelationshipVoKey key); 17 | 18 | int insert(RelationshipVoKey record); 19 | 20 | int insertSelective(RelationshipVoKey record); 21 | 22 | List selectByExample(RelationshipVoExample example); 23 | 24 | int updateByExampleSelective(@Param("record") RelationshipVoKey record, @Param("example") RelationshipVoExample example); 25 | 26 | int updateByExample(@Param("record") RelationshipVoKey record, @Param("example") RelationshipVoExample example); 27 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/LogVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Vo.LogVo; 4 | import com.my.blog.website.modal.Vo.LogVoExample; 5 | import java.util.List; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public interface LogVoMapper { 11 | long countByExample(LogVoExample example); 12 | 13 | int deleteByExample(LogVoExample example); 14 | 15 | int deleteByPrimaryKey(Integer id); 16 | 17 | int insert(LogVo record); 18 | 19 | int insertSelective(LogVo record); 20 | 21 | List selectByExample(LogVoExample example); 22 | 23 | LogVo selectByPrimaryKey(Integer id); 24 | 25 | int updateByExampleSelective(@Param("record") LogVo record, @Param("example") LogVoExample example); 26 | 27 | int updateByExample(@Param("record") LogVo record, @Param("example") LogVoExample example); 28 | 29 | int updateByPrimaryKeySelective(LogVo record); 30 | 31 | int updateByPrimaryKey(LogVo record); 32 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/UserVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Vo.UserVo; 4 | import com.my.blog.website.modal.Vo.UserVoExample; 5 | import java.util.List; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public interface UserVoMapper { 11 | long countByExample(UserVoExample example); 12 | 13 | int deleteByExample(UserVoExample example); 14 | 15 | int deleteByPrimaryKey(Integer uid); 16 | 17 | int insert(UserVo record); 18 | 19 | int insertSelective(UserVo record); 20 | 21 | List selectByExample(UserVoExample example); 22 | 23 | UserVo selectByPrimaryKey(Integer uid); 24 | 25 | int updateByExampleSelective(@Param("record") UserVo record, @Param("example") UserVoExample example); 26 | 27 | int updateByExample(@Param("record") UserVo record, @Param("example") UserVoExample example); 28 | 29 | int updateByPrimaryKeySelective(UserVo record); 30 | 31 | int updateByPrimaryKey(UserVo record); 32 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/controller/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller; 2 | 3 | import com.my.blog.website.exception.TipException; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | /** 10 | * Created by BlueT on 2017/3/4. 11 | */ 12 | @ControllerAdvice 13 | public class GlobalExceptionHandler { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class); 15 | 16 | @ExceptionHandler(value = TipException.class) 17 | public String tipException(Exception e) { 18 | LOGGER.error("find exception:e={}",e.getMessage()); 19 | e.printStackTrace(); 20 | return "comm/error_500"; 21 | } 22 | 23 | 24 | @ExceptionHandler(value = Exception.class) 25 | public String exception(Exception e){ 26 | LOGGER.error("find exception:e={}",e.getMessage()); 27 | e.printStackTrace(); 28 | return "comm/error_404"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/AttachVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Vo.AttachVo; 4 | import com.my.blog.website.modal.Vo.AttachVoExample; 5 | import java.util.List; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public interface AttachVoMapper { 11 | long countByExample(AttachVoExample example); 12 | 13 | int deleteByExample(AttachVoExample example); 14 | 15 | int deleteByPrimaryKey(Integer id); 16 | 17 | int insert(AttachVo record); 18 | 19 | int insertSelective(AttachVo record); 20 | 21 | List selectByExample(AttachVoExample example); 22 | 23 | AttachVo selectByPrimaryKey(Integer id); 24 | 25 | int updateByExampleSelective(@Param("record") AttachVo record, @Param("example") AttachVoExample example); 26 | 27 | int updateByExample(@Param("record") AttachVo record, @Param("example") AttachVoExample example); 28 | 29 | int updateByPrimaryKeySelective(AttachVo record); 30 | 31 | int updateByPrimaryKey(AttachVo record); 32 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/AdminCommons.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | 4 | import com.my.blog.website.modal.Vo.MetaVo; 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * 后台公共函数 10 | *

11 | * Created by 13 on 2017/2/21. 12 | */ 13 | @Component 14 | public final class AdminCommons { 15 | 16 | /** 17 | * 判断category和cat的交集 18 | * 19 | * @param cats 20 | * @return 21 | */ 22 | public static boolean exist_cat(MetaVo category, String cats) { 23 | String[] arr = StringUtils.split(cats, ","); 24 | if (null != arr && arr.length > 0) { 25 | for (String c : arr) { 26 | if (c.trim().equals(category.getName())) { 27 | return true; 28 | } 29 | } 30 | } 31 | return false; 32 | } 33 | 34 | private static final String[] COLORS = {"default", "primary", "success", "info", "warning", "danger", "inverse", "purple", "pink"}; 35 | 36 | public static String rand_color() { 37 | int r = Tools.rand(0, COLORS.length - 1); 38 | return COLORS[r]; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Bo/ArchiveBo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Bo; 2 | 3 | import com.my.blog.website.modal.Vo.ContentVo; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by 13 on 2017/2/23. 10 | */ 11 | public class ArchiveBo implements Serializable { 12 | 13 | private String date; 14 | private String count; 15 | private List articles; 16 | 17 | public String getDate() { 18 | return date; 19 | } 20 | 21 | public void setDate(String date) { 22 | this.date = date; 23 | } 24 | 25 | public String getCount() { 26 | return count; 27 | } 28 | 29 | public void setCount(String count) { 30 | this.count = count; 31 | } 32 | 33 | public List getArticles() { 34 | return articles; 35 | } 36 | 37 | public void setArticles(List articles) { 38 | this.articles = articles; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "Archive [" + 44 | "date='" + date + '\'' + 45 | ", count='" + count + '\'' + 46 | ", articles=" + articles + 47 | ']'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/interceptor/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.interceptor; 2 | 3 | 4 | import com.my.blog.website.utils.TaleUtils; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 9 | 10 | import javax.annotation.Resource; 11 | 12 | /** 13 | * 向mvc中添加自定义组件 14 | * Created by BlueT on 2017/3/9. 15 | */ 16 | @Component 17 | public class WebMvcConfig extends WebMvcConfigurerAdapter { 18 | @Resource 19 | private BaseInterceptor baseInterceptor; 20 | @Override 21 | public void addInterceptors(InterceptorRegistry registry) { 22 | registry.addInterceptor(baseInterceptor); 23 | } 24 | 25 | /** 26 | * 添加静态资源文件,外部可以直接访问地址 27 | * @param registry 28 | */ 29 | @Override 30 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 31 | registry.addResourceHandler("/upload/**").addResourceLocations("file:"+ TaleUtils.getUplodFilePath()+"upload/"); 32 | super.addResourceHandlers(registry); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

221.个人博客管理系统

2 | 3 | - 完整代码获取地址:从戎源码网 ([https://armycodes.com/](https://armycodes.com/)) 4 | - 技术探讨、资料分享,请加QQ群:692619798 5 | - 作者微信:19941326836 QQ:952045282 6 | - 承接计算机毕业设计、Java毕业设计、Python毕业设计、深度学习、机器学习 7 | - 选题+开题报告+任务书+程序定制+安装调试+论文+答辩ppt 一条龙服务 8 | - 所有选题地址 ([https://github.com/YuLin-Coder/AllProjectCatalog](https://github.com/YuLin-Coder/AllProjectCatalog)) 9 | 10 | ## 项目介绍 11 | 基于springboot的个人博客管理系统【含报告】:前端 html、jquery、bootstrap,后端 maven、springmvc、spring、mybatis;角色分为管理员、用户;集成文章管理、评论管理、分类管理、文件管理等功能于一体的系统。 12 | 13 | ## 功能介绍 14 | 15 | - 仪表盘:发表文章数、收到了留言数、上传附件数,友链好友数,最新文章、最新留言、系统日志 16 | - 文章管理:文章的增删改查,文章预览,存为草稿,开启评论 17 | - 页面管理:页面信息的增删改查,页面预览 18 | - 评论管理:评论信息列表查询,评论审核,评论删除 19 | - 分类标签管理:分类信息的增删改查,标签信息的增删改查 20 | - 文件管理:文件信息列表查询,文件上传,文件复制,文件删除 21 | - 友链管理:友链信息的增删改查 22 | - 系统设置:全局设置,个性化设置,系统备份 23 | 24 | ## 环境 25 | 26 | - IntelliJ IDEA 2021.3 27 | 28 | - Mysql 5.7.26 29 | 30 | - JDK 1.8 31 | 32 | ## 运行截图 33 | 34 | ![](screenshot/1.png) 35 | 36 | ![](screenshot/2.png) 37 | 38 | ![](screenshot/3.png) 39 | 40 | ![](screenshot/4.png) 41 | 42 | ![](screenshot/5.png) 43 | 44 | ![](screenshot/6.png) 45 | 46 | ![](screenshot/7.png) 47 | 48 | ![](screenshot/8.png) 49 | -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/links.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |

友情链接

8 | 13 |

链接须知

14 |
15 |
    16 |
  • 请确定贵站可以稳定运营

  • 17 |
  • 原创博客优先,技术类博客优先,设计、视觉类博客优先

  • 18 |
  • 经常过来访问和评论,眼熟的

  • 19 |
20 |
21 |

基本信息

22 |

23 |             网站名称:猿 Blog( zhisheng 的技术分享)
24 |             网站地址:http://www.54tianzhisheng.cn
25 | 26 |

我的邮箱:zhisheng2018@gmail.com

27 |

暂时先这样,同时欢迎互换友链 ^_^

28 |

还有,我会不定时对无法访问的网址进行清理,请保证自己的链接长期有效

29 |
30 | 31 |
32 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/OptionVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Vo.OptionVo; 4 | import com.my.blog.website.modal.Vo.OptionVoExample; 5 | 6 | import java.util.List; 7 | 8 | import org.apache.ibatis.annotations.Param; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public interface OptionVoMapper { 13 | long countByExample(OptionVoExample example); 14 | 15 | int deleteByExample(OptionVoExample example); 16 | 17 | int deleteByPrimaryKey(String name); 18 | 19 | int insert(OptionVo record); 20 | 21 | int insertSelective(OptionVo record); 22 | 23 | List selectByExample(OptionVoExample example); 24 | 25 | OptionVo selectByPrimaryKey(String name); 26 | 27 | int updateByExampleSelective(@Param("record") OptionVo record, @Param("example") OptionVoExample example); 28 | 29 | int updateByExample(@Param("record") OptionVo record, @Param("example") OptionVoExample example); 30 | 31 | int updateByPrimaryKeySelective(OptionVo record); 32 | 33 | int updateByPrimaryKey(OptionVo record); 34 | 35 | /** 36 | * 批量保存 37 | * @param optionVos list 38 | * @return 保存的个数 39 | */ 40 | int insertOptions(List optionVos); 41 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Bo/CommentBo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Bo; 2 | 3 | import com.my.blog.website.modal.Vo.CommentVo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 返回页面的评论,包含父子评论内容 9 | * Created by 13 on 2017/2/24. 10 | */ 11 | public class CommentBo extends CommentVo { 12 | 13 | private int levels; 14 | private List children; 15 | 16 | public CommentBo(CommentVo comments) { 17 | setAuthor(comments.getAuthor()); 18 | setMail(comments.getMail()); 19 | setCoid(comments.getCoid()); 20 | setAuthorId(comments.getAuthorId()); 21 | setUrl(comments.getUrl()); 22 | setCreated(comments.getCreated()); 23 | setAgent(comments.getAgent()); 24 | setIp(comments.getIp()); 25 | setContent(comments.getContent()); 26 | setOwnerId(comments.getOwnerId()); 27 | setCid(comments.getCid()); 28 | } 29 | 30 | public int getLevels() { 31 | return levels; 32 | } 33 | 34 | public void setLevels(int levels) { 35 | this.levels = levels; 36 | } 37 | 38 | public List getChildren() { 39 | return children; 40 | } 41 | 42 | public void setChildren(List children) { 43 | this.children = children; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/MetaVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.dto.MetaDto; 4 | import com.my.blog.website.modal.Vo.MetaVo; 5 | import com.my.blog.website.modal.Vo.MetaVoExample; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.apache.ibatis.annotations.Param; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public interface MetaVoMapper { 15 | long countByExample(MetaVoExample example); 16 | 17 | int deleteByExample(MetaVoExample example); 18 | 19 | int deleteByPrimaryKey(Integer mid); 20 | 21 | int insert(MetaVo record); 22 | 23 | int insertSelective(MetaVo record); 24 | 25 | List selectByExample(MetaVoExample example); 26 | 27 | MetaVo selectByPrimaryKey(Integer mid); 28 | 29 | int updateByExampleSelective(@Param("record") MetaVo record, @Param("example") MetaVoExample example); 30 | 31 | int updateByExample(@Param("record") MetaVo record, @Param("example") MetaVoExample example); 32 | 33 | int updateByPrimaryKeySelective(MetaVo record); 34 | 35 | int updateByPrimaryKey(MetaVo record); 36 | 37 | List selectFromSql(Map paraMap); 38 | 39 | MetaDto selectDtoByNameAndType(@Param("name") String name,@Param("type") String type); 40 | 41 | Integer countWithSql(Integer mid); 42 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Bo/StatisticsBo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Bo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 后台统计对象 7 | */ 8 | public class StatisticsBo implements Serializable { 9 | 10 | private Long articles; 11 | private Long comments; 12 | private Long links; 13 | private Long attachs; 14 | 15 | public Long getArticles() { 16 | return articles; 17 | } 18 | 19 | public void setArticles(Long articles) { 20 | this.articles = articles; 21 | } 22 | 23 | public Long getComments() { 24 | return comments; 25 | } 26 | 27 | public void setComments(Long comments) { 28 | this.comments = comments; 29 | } 30 | 31 | public Long getLinks() { 32 | return links; 33 | } 34 | 35 | public void setLinks(Long links) { 36 | this.links = links; 37 | } 38 | 39 | public Long getAttachs() { 40 | return attachs; 41 | } 42 | 43 | public void setAttachs(Long attachs) { 44 | this.attachs = attachs; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "StatisticsBo{" + 50 | "articles=" + articles + 51 | ", comments=" + comments + 52 | ", links=" + links + 53 | ", attachs=" + attachs + 54 | '}'; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/CommentVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Vo.CommentVo; 4 | import com.my.blog.website.modal.Vo.CommentVoExample; 5 | 6 | import java.util.List; 7 | import org.apache.ibatis.annotations.Param; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public interface CommentVoMapper { 12 | long countByExample(CommentVoExample example); 13 | 14 | int deleteByExample(CommentVoExample example); 15 | 16 | int deleteByPrimaryKey(Integer coid); 17 | 18 | int insert(CommentVo record); 19 | 20 | int insertSelective(CommentVo record); 21 | 22 | List selectByExampleWithBLOBs(CommentVoExample example); 23 | 24 | List selectByExample(CommentVoExample example); 25 | 26 | CommentVo selectByPrimaryKey(Integer coid); 27 | 28 | int updateByExampleSelective(@Param("record") CommentVo record, @Param("example") CommentVoExample example); 29 | 30 | int updateByExampleWithBLOBs(@Param("record") CommentVo record, @Param("example") CommentVoExample example); 31 | 32 | int updateByExample(@Param("record") CommentVo record, @Param("example") CommentVoExample example); 33 | 34 | int updateByPrimaryKeySelective(CommentVo record); 35 | 36 | int updateByPrimaryKeyWithBLOBs(CommentVo record); 37 | 38 | int updateByPrimaryKey(CommentVo record); 39 | } -------------------------------------------------------------------------------- /src/main/resources/templates/comm/error_404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404(找不到页面)- My Blog 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 |
22 |
23 |

404!

24 |

很抱歉,没有找到这个页面!

25 |

26 | 返回首页 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/db/Row.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup.db; 2 | 3 | import java.util.Date; 4 | 5 | public class Row { 6 | private Object[] data; 7 | private DataTable dataTable; 8 | 9 | public Row(DataTable dataTable, Object[] data) { 10 | this.dataTable = dataTable; 11 | this.data = data; 12 | } 13 | 14 | public Object get(String columnLabel) { 15 | return get(dataTable.getColumns().indexByLabel(columnLabel)); 16 | } 17 | 18 | public Object get(int index) { 19 | return data[index]; 20 | } 21 | 22 | public String getString(int index) { 23 | return String.valueOf(get(index)); 24 | } 25 | 26 | public String getString(String label) { 27 | return String.valueOf(get(label)); 28 | } 29 | 30 | public Integer getInteger(String label) { 31 | return (Integer) (get(label)); 32 | } 33 | 34 | public Date getDate(int index) { 35 | return (Date) get(index); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | if (data == null || data.length == 0) { 41 | return "{}"; 42 | } 43 | String s = "{" + String.valueOf(data[0]); 44 | for (int i = 1; i < data.length; i++) { 45 | s += ", " + String.valueOf(data[i]); 46 | } 47 | s += "}"; 48 | return s; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/my/blog/website/TranscationTest.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website; 2 | 3 | import com.my.blog.website.exception.TipException; 4 | import com.my.blog.website.modal.Vo.UserVo; 5 | import com.my.blog.website.service.IUserService; 6 | import com.my.blog.website.service.IOptionService; 7 | import org.junit.Ignore; 8 | import org.junit.runner.RunWith; 9 | import org.mybatis.spring.annotation.MapperScan; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import javax.annotation.Resource; 15 | 16 | /** 17 | * 测试数据库事务 18 | * Created by BlueT on 2017/3/8. 19 | */ 20 | @MapperScan("com.my.blog.website.dao") 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest 23 | @Transactional(rollbackFor = TipException.class) 24 | public class TranscationTest { 25 | 26 | @Resource 27 | private IUserService userService; 28 | 29 | @Resource 30 | private IOptionService optionService; 31 | 32 | @org.junit.Test 33 | @Ignore 34 | public void test() { 35 | UserVo user = new UserVo(); 36 | user.setUsername("wangqiang111"); 37 | user.setPassword("123456"); 38 | user.setEmail("8888"); 39 | userService.insertUser(user); 40 | optionService.insertOption("site_keywords", "qwqwq"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/my/blog/website/controller/IndexControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.mock.web.MockHttpServletRequest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | import org.springframework.test.web.servlet.MockMvc; 12 | import org.springframework.test.web.servlet.RequestBuilder; 13 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 14 | import org.springframework.test.web.servlet.result.MockMvcResultHandlers; 15 | import org.springframework.test.web.servlet.result.MockMvcResultMatchers; 16 | 17 | import static org.junit.Assert.*; 18 | 19 | /** 20 | * 接口测试方法 21 | * Created by BlueT on 2017/3/22. 22 | */ 23 | @RunWith(SpringRunner.class) 24 | @SpringBootTest 25 | @AutoConfigureMockMvc 26 | public class IndexControllerTest { 27 | 28 | @Autowired 29 | private MockMvc mockMvc; 30 | @Test 31 | @Ignore 32 | public void index() throws Exception { 33 | mockMvc.perform(MockMvcRequestBuilders.get("")).andExpect(MockMvcResultMatchers.status().isOk()); 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/ICommentService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.my.blog.website.modal.Vo.CommentVo; 5 | import com.my.blog.website.modal.Vo.CommentVoExample; 6 | import com.my.blog.website.modal.Bo.CommentBo; 7 | 8 | /** 9 | * Created by BlueT on 2017/3/16. 10 | */ 11 | public interface ICommentService { 12 | 13 | /** 14 | * 保存对象 15 | * @param commentVo 16 | */ 17 | void insertComment(CommentVo commentVo); 18 | 19 | /** 20 | * 获取文章下的评论 21 | * @param cid 22 | * @param page 23 | * @param limit 24 | * @return CommentBo 25 | */ 26 | PageInfo getComments(Integer cid, int page, int limit); 27 | 28 | /** 29 | * 获取文章下的评论 30 | * @param commentVoExample 31 | * @param page 32 | * @param limit 33 | * @return CommentVo 34 | */ 35 | PageInfo getCommentsWithPage(CommentVoExample commentVoExample, int page, int limit); 36 | 37 | 38 | /** 39 | * 根据主键查询评论 40 | * @param coid 41 | * @return 42 | */ 43 | CommentVo getCommentById(Integer coid); 44 | 45 | 46 | /** 47 | * 删除评论,暂时没用 48 | * @param coid 49 | * @param cid 50 | * @throws Exception 51 | */ 52 | void delete(Integer coid, Integer cid); 53 | 54 | /** 55 | * 更新评论状态 56 | * @param comments 57 | */ 58 | void update(CommentVo comments); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/tagsinput/jquery.tagsinput.css: -------------------------------------------------------------------------------- 1 | div.tagsinput { 2 | border:1px solid #ccc; 3 | background: #FFF; 4 | padding:5px; 5 | width:300px; 6 | height:100px; 7 | overflow-y: auto; 8 | -moz-border-radius: 2px; 9 | -webkit-border-radius: 2px; 10 | border-radius: 2px; 11 | } 12 | 13 | div.tagsinput span.tag { 14 | display: block; 15 | float: left; 16 | padding: 2px 5px; 17 | text-decoration:none; 18 | background: #317eeb; 19 | color: #fff; 20 | margin-right: 5px; 21 | margin-bottom:5px; 22 | font-size:13px; 23 | -moz-border-radius: 2px; 24 | -webkit-border-radius: 2px; 25 | border-radius: 2px; 26 | } 27 | 28 | div.tagsinput span.tag a { 29 | font-weight: bold; 30 | color: #fff; 31 | opacity: 0.5; 32 | text-decoration: none; 33 | font-size: 11px; 34 | } 35 | 36 | div.tagsinput span.tag a:hover { 37 | opacity: 1; 38 | } 39 | 40 | div.tagsinput input { 41 | width: 80px; 42 | margin: 0px; 43 | font-size: 13px; 44 | border: 1px solid transparent; 45 | padding: 5px; 46 | background: transparent; 47 | color: #000; 48 | outline: 0px; 49 | margin-right: 5px; 50 | margin-bottom: 5px; 51 | } 52 | 53 | div.tagsinput div { 54 | display: block; 55 | float: left; 56 | } 57 | 58 | .tags_clear { 59 | clear: both; 60 | width: 100%; 61 | height: 0px; 62 | } 63 | 64 | .not_valid { 65 | background: #FBD8DB !important; 66 | color: #90111A !important; 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/controller/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller; 2 | 3 | import com.my.blog.website.modal.Vo.UserVo; 4 | import com.my.blog.website.utils.TaleUtils; 5 | import com.my.blog.website.utils.MapCache; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | /** 10 | * Created by 13 on 2017/2/21. 11 | */ 12 | public abstract class BaseController { 13 | 14 | public static String THEME = "themes/default"; 15 | 16 | protected MapCache cache = MapCache.single(); 17 | 18 | /** 19 | * 主页的页面主题 20 | * @param viewName 21 | * @return 22 | */ 23 | public String render(String viewName) { 24 | return THEME + "/" + viewName; 25 | } 26 | 27 | public BaseController title(HttpServletRequest request, String title) { 28 | request.setAttribute("title", title); 29 | return this; 30 | } 31 | 32 | public BaseController keywords(HttpServletRequest request, String keywords) { 33 | request.setAttribute("keywords", keywords); 34 | return this; 35 | } 36 | 37 | /** 38 | * 获取请求绑定的登录对象 39 | * @param request 40 | * @return 41 | */ 42 | public UserVo user(HttpServletRequest request) { 43 | return TaleUtils.getLoginUser(request); 44 | } 45 | 46 | public Integer getUid(HttpServletRequest request){ 47 | return this.user(request).getUid(); 48 | } 49 | 50 | public String render_404() { 51 | return "comm/error_404"; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/resources/templates/comm/error_500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 500(服务器出差错了)- My Blog 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 |
22 |
23 |

500

24 |

服务器出了点差错.



25 |

可以尝试向社区发出求助 New Issues

26 | 返回首页 27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/AttachVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class AttachVo implements Serializable { 9 | private Integer id; 10 | 11 | private String fname; 12 | 13 | private String ftype; 14 | 15 | private String fkey; 16 | 17 | private Integer authorId; 18 | 19 | private Integer created; 20 | 21 | private static final long serialVersionUID = 1L; 22 | 23 | public Integer getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Integer id) { 28 | this.id = id; 29 | } 30 | 31 | public String getFname() { 32 | return fname; 33 | } 34 | 35 | public void setFname(String fname) { 36 | this.fname = fname; 37 | } 38 | 39 | public String getFtype() { 40 | return ftype; 41 | } 42 | 43 | public void setFtype(String ftype) { 44 | this.ftype = ftype; 45 | } 46 | 47 | public String getFkey() { 48 | return fkey; 49 | } 50 | 51 | public void setFkey(String fkey) { 52 | this.fkey = fkey; 53 | } 54 | 55 | public Integer getAuthorId() { 56 | return authorId; 57 | } 58 | 59 | public void setAuthorId(Integer authorId) { 60 | this.authorId = authorId; 61 | } 62 | 63 | public Integer getCreated() { 64 | return created; 65 | } 66 | 67 | public void setCreated(Integer created) { 68 | this.created = created; 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dao/ContentVoMapper.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dao; 2 | 3 | import com.my.blog.website.modal.Bo.ArchiveBo; 4 | import com.my.blog.website.modal.Vo.ContentVo; 5 | import com.my.blog.website.modal.Vo.ContentVoExample; 6 | 7 | import java.util.List; 8 | import org.apache.ibatis.annotations.Param; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public interface ContentVoMapper { 13 | long countByExample(ContentVoExample example); 14 | 15 | int deleteByExample(ContentVoExample example); 16 | 17 | int deleteByPrimaryKey(Integer cid); 18 | 19 | int insert(ContentVo record); 20 | 21 | int insertSelective(ContentVo record); 22 | 23 | List selectByExampleWithBLOBs(ContentVoExample example); 24 | 25 | List selectByExample(ContentVoExample example); 26 | 27 | ContentVo selectByPrimaryKey(Integer cid); 28 | 29 | int updateByExampleSelective(@Param("record") ContentVo record, @Param("example") ContentVoExample example); 30 | 31 | int updateByExampleWithBLOBs(@Param("record") ContentVo record, @Param("example") ContentVoExample example); 32 | 33 | int updateByExample(@Param("record") ContentVo record, @Param("example") ContentVoExample example); 34 | 35 | int updateByPrimaryKeySelective(ContentVo record); 36 | 37 | int updateByPrimaryKeyWithBLOBs(ContentVo record); 38 | 39 | int updateByPrimaryKey(ContentVo record); 40 | 41 | List findReturnArchiveBo(); 42 | 43 | List findByCatalog(Integer mid); 44 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/constant/WebConst.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.constant; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by BlueT on 2017/3/3. 12 | */ 13 | @Component 14 | public class WebConst { 15 | /** 16 | * 存储安装信息的配置文件名称 17 | */ 18 | public static final String INSTALL_FILE_CONF = "install.lock"; 19 | 20 | public static Map initConfig = new HashMap<>(); 21 | 22 | 23 | public static String LOGIN_SESSION_KEY = "login_user"; 24 | 25 | public static final String USER_IN_COOKIE = "S_L_ID"; 26 | 27 | /** 28 | * aes加密加盐 29 | */ 30 | public static String AES_SALT = "0123456789abcdef"; 31 | 32 | /** 33 | * 最大获取文章条数 34 | */ 35 | public static final int MAX_POSTS = 9999; 36 | 37 | /** 38 | * 最大页码 39 | */ 40 | public static final int MAX_PAGE = 100; 41 | 42 | /** 43 | * 文章最多可以输入的文字数 44 | */ 45 | public static final int MAX_TEXT_COUNT = 200000; 46 | 47 | /** 48 | * 文章标题最多可以输入的文字个数 49 | */ 50 | public static final int MAX_TITLE_COUNT = 200; 51 | 52 | /** 53 | * 点击次数超过多少更新到数据库 54 | */ 55 | public static final int HIT_EXCEED = 10; 56 | 57 | /** 58 | * 上传文件最大1M 59 | */ 60 | public static Integer MAX_FILE_SIZE = 1048576; 61 | 62 | /** 63 | * 要过滤的ip列表 64 | */ 65 | public static final Set BLOCK_IPS = new HashSet<>(16); 66 | } 67 | -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/archives.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |
16 | 17 |
18 |
19 |
发布于
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 31 |
32 | -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/post.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |

8 | 9 |

10 |
11 | 12 | / / / 13 | 浏览 14 |
15 |
16 |
17 | 18 | 19 | 23 |
24 |
25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/ISiteService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.my.blog.website.dto.MetaDto; 4 | import com.my.blog.website.modal.Bo.ArchiveBo; 5 | import com.my.blog.website.modal.Bo.BackResponseBo; 6 | import com.my.blog.website.modal.Bo.StatisticsBo; 7 | import com.my.blog.website.modal.Vo.CommentVo; 8 | import com.my.blog.website.modal.Vo.ContentVo; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 站点服务 14 | * 15 | * Created by 13 on 2017/2/23. 16 | */ 17 | public interface ISiteService { 18 | 19 | 20 | /** 21 | * 最新收到的评论 22 | * 23 | * @param limit 24 | * @return 25 | */ 26 | List recentComments(int limit); 27 | 28 | /** 29 | * 最新发表的文章 30 | * 31 | * @param limit 32 | * @return 33 | */ 34 | List recentContents(int limit); 35 | 36 | /** 37 | * 查询一条评论 38 | * @param coid 39 | * @return 40 | */ 41 | CommentVo getComment(Integer coid); 42 | 43 | /** 44 | * 系统备份 45 | * @param bk_type 46 | * @param bk_path 47 | * @param fmt 48 | * @return 49 | */ 50 | BackResponseBo backup(String bk_type, String bk_path, String fmt) throws Exception; 51 | 52 | 53 | /** 54 | * 获取后台统计数据 55 | * 56 | * @return 57 | */ 58 | StatisticsBo getStatistics(); 59 | 60 | /** 61 | * 查询文章归档 62 | * 63 | * @return 64 | */ 65 | List getArchives(); 66 | 67 | /** 68 | * 获取分类/标签列表 69 | * @return 70 | */ 71 | List metas(String type, String orderBy, int limit); 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_GREEN} 2 | 3 | bbbbbbbb 4 | b::::::b lllllll 5 | b::::::b l:::::l 6 | b::::::b l:::::l 7 | b:::::b l:::::l 8 | b:::::bbbbbbbbb l::::l ooooooooooo ggggggggg ggggg 9 | b::::::::::::::bb l::::l oo:::::::::::oo g:::::::::ggg::::g 10 | b::::::::::::::::b l::::l o:::::::::::::::o g:::::::::::::::::g 11 | b:::::bbbbb:::::::b l::::l o:::::ooooo:::::og::::::ggggg::::::gg 12 | b:::::b b::::::b l::::l o::::o o::::og:::::g g:::::g 13 | b:::::b b:::::b l::::l o::::o o::::og:::::g g:::::g 14 | b:::::b b:::::b l::::l o::::o o::::og:::::g g:::::g 15 | b:::::b b:::::b l::::l o::::o o::::og::::::g g:::::g 16 | b:::::bbbbbb::::::bl::::::lo:::::ooooo:::::og:::::::ggggg:::::g 17 | b::::::::::::::::b l::::::lo:::::::::::::::o g::::::::::::::::g 18 | b:::::::::::::::b l::::::l oo:::::::::::oo gg::::::::::::::g 19 | bbbbbbbbbbbbbbbb llllllll ooooooooooo gggggggg::::::g 20 | g:::::g 21 | gggggg g:::::g 22 | g:::::gg gg:::::g 23 | g::::::ggg:::::::g 24 | gg:::::::::::::g 25 | ggg::::::ggg 26 | gggggg 27 | ${AnsiColor.BLACK} 28 | Application Version: ${application.version}${application.formatted-version} 29 | Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/IMetaService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.my.blog.website.dto.MetaDto; 4 | import com.my.blog.website.modal.Vo.MetaVo; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 分类信息service接口 10 | * Created by BlueT on 2017/3/17. 11 | */ 12 | public interface IMetaService { 13 | /** 14 | * 根据类型和名字查询项 15 | * 16 | * @param type 17 | * @param name 18 | * @return 19 | */ 20 | MetaDto getMeta(String type, String name); 21 | 22 | /** 23 | * 根据文章id获取项目个数 24 | * @param mid 25 | * @return 26 | */ 27 | Integer countMeta(Integer mid); 28 | 29 | /** 30 | * 根据类型查询项目列表 31 | * @param types 32 | * @return 33 | */ 34 | List getMetas(String types); 35 | 36 | 37 | /** 38 | * 保存多个项目 39 | * @param cid 40 | * @param names 41 | * @param type 42 | */ 43 | void saveMetas(Integer cid, String names, String type); 44 | 45 | /** 46 | * 保存项目 47 | * @param type 48 | * @param name 49 | * @param mid 50 | */ 51 | void saveMeta(String type, String name, Integer mid); 52 | 53 | /** 54 | * 根据类型查询项目列表,带项目下面的文章数 55 | * @return 56 | */ 57 | List getMetaList(String type, String orderby, int limit); 58 | 59 | /** 60 | * 删除项目 61 | * @param mid 62 | */ 63 | void delete(int mid); 64 | 65 | /** 66 | * 保存项目 67 | * @param metas 68 | */ 69 | void saveMeta(MetaVo metas); 70 | 71 | /** 72 | * 更新项目 73 | * @param metas 74 | */ 75 | void update(MetaVo metas); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/LogVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class LogVo implements Serializable { 9 | /** 10 | * 日志主键 11 | */ 12 | private Integer id; 13 | 14 | /** 15 | * 产生的动作 16 | */ 17 | private String action; 18 | 19 | /** 20 | * 产生的数据 21 | */ 22 | private String data; 23 | 24 | /** 25 | * 发生人id 26 | */ 27 | private Integer authorId; 28 | 29 | /** 30 | * 日志产生的ip 31 | */ 32 | private String ip; 33 | 34 | /** 35 | * 日志创建时间 36 | */ 37 | private Integer created; 38 | 39 | 40 | 41 | private static final long serialVersionUID = 1L; 42 | 43 | public Integer getId() { 44 | return id; 45 | } 46 | 47 | public void setId(Integer id) { 48 | this.id = id; 49 | } 50 | 51 | public String getAction() { 52 | return action; 53 | } 54 | 55 | public void setAction(String action) { 56 | this.action = action; 57 | } 58 | 59 | public String getData() { 60 | return data; 61 | } 62 | 63 | public void setData(String data) { 64 | this.data = data; 65 | } 66 | 67 | public Integer getAuthorId() { 68 | return authorId; 69 | } 70 | 71 | public void setAuthorId(Integer authorId) { 72 | this.authorId = authorId; 73 | } 74 | 75 | public String getIp() { 76 | return ip; 77 | } 78 | 79 | public void setIp(String ip) { 80 | this.ip = ip; 81 | } 82 | 83 | public Integer getCreated() { 84 | return created; 85 | } 86 | 87 | public void setCreated(Integer created) { 88 | this.created = created; 89 | } 90 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/LogAspect.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | import org.aspectj.lang.JoinPoint; 4 | import org.aspectj.lang.annotation.AfterReturning; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.aspectj.lang.annotation.Before; 7 | import org.aspectj.lang.annotation.Pointcut; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.context.request.RequestContextHolder; 12 | import org.springframework.web.context.request.ServletRequestAttributes; 13 | 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.sql.DataSource; 16 | import java.util.Arrays; 17 | 18 | /** 19 | * 借口aop 20 | * Created by wangq on 2017/3/24. 21 | */ 22 | @Aspect 23 | @Component 24 | public class LogAspect { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(DataSource.class); 26 | 27 | @Pointcut("execution(public * com.my.blog.website.controller..*.*(..))") 28 | public void webLog(){} 29 | 30 | @Before("webLog()") 31 | public void doBefore(JoinPoint joinPoint) throws Throwable { 32 | // 接收到请求,记录请求内容 33 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 34 | HttpServletRequest request = attributes.getRequest(); 35 | // 记录下请求内容 36 | LOGGER.info("URL : " + request.getRequestURL().toString() + ",IP : " + request.getRemoteAddr() + ",CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + ",ARGS : " + Arrays.toString(joinPoint.getArgs())); 37 | } 38 | 39 | @AfterReturning(returning = "object", pointcut = "webLog()") 40 | public void doAfterReturning(Object object) throws Throwable { 41 | // 处理完请求,返回内容 42 | LOGGER.info("RESPONSE : " + object); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/dto/DataSource.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.dto; 2 | 3 | /** 4 | * 建立数据库连接的参数对象 5 | * Created by BlueT on 2017/3/4. 6 | */ 7 | public class DataSource { 8 | 9 | /** 10 | * 数据库url 11 | */ 12 | private String url; 13 | 14 | /** 15 | * 数据库用户名 16 | */ 17 | private String username; 18 | 19 | /** 20 | * 数据库密码 21 | */ 22 | private String password; 23 | 24 | /** 25 | * 数据库驱动名称 26 | */ 27 | private String drivercClassName; 28 | 29 | /** 30 | * 数据库名字 31 | */ 32 | private String dbName; 33 | 34 | public String getDbName() { 35 | return dbName; 36 | } 37 | 38 | public void setDbName(String dbName) { 39 | this.dbName = dbName; 40 | } 41 | 42 | public String getUrl() { 43 | return url; 44 | } 45 | 46 | public String getUsername() { 47 | return username; 48 | } 49 | 50 | public String getPassword() { 51 | return password; 52 | } 53 | 54 | public String getDrivercClassName() { 55 | return drivercClassName; 56 | } 57 | 58 | public void setUrl(String url) { 59 | this.url = url; 60 | } 61 | 62 | public void setUsername(String username) { 63 | this.username = username; 64 | } 65 | 66 | public void setPassword(String password) { 67 | this.password = password; 68 | } 69 | 70 | public void setDrivercClassName(String drivercClassName) { 71 | this.drivercClassName = drivercClassName; 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | return "DataSource{" + 77 | "url='" + url + '\'' + 78 | ", username='" + username + '\'' + 79 | ", password='" + password + '\'' + 80 | ", drivercClassName='" + drivercClassName + '\'' + 81 | ", dbName='" + dbName + '\'' + 82 | '}'; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/MetaVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class MetaVo implements Serializable { 9 | /** 10 | * 项目主键 11 | */ 12 | private Integer mid; 13 | 14 | /** 15 | * 名称 16 | */ 17 | private String name; 18 | 19 | /** 20 | * 项目缩略名 21 | */ 22 | private String slug; 23 | 24 | /** 25 | * 项目类型 26 | */ 27 | private String type; 28 | 29 | /** 30 | * 选项描述 31 | */ 32 | private String description; 33 | 34 | /** 35 | * 项目排序 36 | */ 37 | private Integer sort; 38 | 39 | private Integer parent; 40 | 41 | private static final long serialVersionUID = 1L; 42 | 43 | public Integer getMid() { 44 | return mid; 45 | } 46 | 47 | public void setMid(Integer mid) { 48 | this.mid = mid; 49 | } 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | public void setName(String name) { 56 | this.name = name; 57 | } 58 | 59 | public String getSlug() { 60 | return slug; 61 | } 62 | 63 | public void setSlug(String slug) { 64 | this.slug = slug; 65 | } 66 | 67 | public String getType() { 68 | return type; 69 | } 70 | 71 | public void setType(String type) { 72 | this.type = type; 73 | } 74 | 75 | public String getDescription() { 76 | return description; 77 | } 78 | 79 | public void setDescription(String description) { 80 | this.description = description; 81 | } 82 | 83 | public Integer getSort() { 84 | return sort; 85 | } 86 | 87 | public void setSort(Integer sort) { 88 | this.sort = sort; 89 | } 90 | 91 | public Integer getParent() { 92 | return parent; 93 | } 94 | 95 | public void setParent(Integer parent) { 96 | this.parent = parent; 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/md/js/jquery.scrollto.js: -------------------------------------------------------------------------------- 1 | (function(c){var a=c.scrollTo=function(f,e,d){c(window).scrollTo(f,e,d)};a.defaults={axis:"xy",duration:parseFloat(c.fn.jquery)>=1.3?0:1,limit:true};a.window=function(d){return c(window)._scrollable()};c.fn._scrollable=function(){return this.map(function(){var e=this,d=!e.nodeName||c.inArray(e.nodeName.toLowerCase(),["iframe","#document","html","body"])!=-1;if(!d){return e}var f=(e.contentWindow||e).document||e.ownerDocument||e;return/webkit/i.test(navigator.userAgent)||f.compatMode=="BackCompat"?f.body:f.documentElement})};c.fn.scrollTo=function(f,e,d){if(typeof e=="object"){d=e;e=0}if(typeof d=="function"){d={onAfter:d}}if(f=="max"){f=9000000000}d=c.extend({},a.defaults,d);e=e||d.duration;d.queue=d.queue&&d.axis.length>1;if(d.queue){e/=2}d.offset=b(d.offset);d.over=b(d.over);return this._scrollable().each(function(){if(f==null){return}var l=this,j=c(l),k=f,i,g={},m=j.is("html,body");switch(typeof k){case"number":case"string":if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(k)){k=b(k);break}k=c(k,this);if(!k.length){return}case"object":if(k.is||k.style){i=(k=c(k)).offset()}}c.each(d.axis.split(""),function(q,r){var s=r=="x"?"Left":"Top",u=s.toLowerCase(),p="scroll"+s,o=l[p],n=a.max(l,r);if(i){g[p]=i[u]+(m?0:o-j.offset()[u]);if(d.margin){g[p]-=parseInt(k.css("margin"+s))||0;g[p]-=parseInt(k.css("border"+s+"Width"))||0}g[p]+=d.offset[u]||0;if(d.over[u]){g[p]+=k[r=="x"?"width":"height"]()*d.over[u]}}else{var t=k[u];g[p]=t.slice&&t.slice(-1)=="%"?parseFloat(t)/100*n:t}if(d.limit&&/^\d+$/.test(g[p])){g[p]=g[p]<=0?0:Math.min(g[p],n)}if(!q&&d.queue){if(o!=g[p]){h(d.onAfterFirst)}delete g[p]}});h(d.onAfter);function h(n){j.animate(g,e,d.easing,n&&function(){n.call(this,f,d)})}}).end()};a.max=function(j,i){var h=i=="x"?"Width":"Height",e="scroll"+h;if(!c(j).is("html,body")){return j[e]-c(j)[h.toLowerCase()]()}var g="client"+h,f=j.ownerDocument.documentElement,d=j.ownerDocument.body;return Math.max(f[e],d[e])-Math.min(f[g],d[g])};function b(d){return typeof d=="object"?d:{top:d,left:d}}})(jQuery); -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 |
10 | 12 | 13 | 14 |
15 |
16 |
17 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/templates/comm/macros.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 |
23 |
24 | 46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/impl/OptionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service.impl; 2 | 3 | import com.my.blog.website.dao.OptionVoMapper; 4 | import com.my.blog.website.modal.Vo.OptionVo; 5 | import com.my.blog.website.modal.Vo.OptionVoExample; 6 | import com.my.blog.website.service.IOptionService; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Service; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * options表的service 17 | * Created by BlueT on 2017/3/7. 18 | */ 19 | @Service 20 | public class OptionServiceImpl implements IOptionService { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(OptionServiceImpl.class); 23 | 24 | @Resource 25 | private OptionVoMapper optionDao; 26 | 27 | @Override 28 | public void insertOption(OptionVo optionVo) { 29 | LOGGER.debug("Enter insertOption method:optionVo={}" ,optionVo); 30 | optionDao.insertSelective(optionVo); 31 | LOGGER.debug("Exit insertOption method."); 32 | } 33 | 34 | @Override 35 | public void insertOption(String name, String value) { 36 | LOGGER.debug("Enter insertOption method:name={},value={}",name,value ); 37 | OptionVo optionVo = new OptionVo(); 38 | optionVo.setName(name); 39 | optionVo.setValue(value); 40 | if(optionDao.selectByExample(new OptionVoExample()).size()==0){ 41 | optionDao.insertSelective(optionVo); 42 | }else{ 43 | optionDao.updateByPrimaryKeySelective(optionVo); 44 | } 45 | LOGGER.debug("Exit insertOption method."); 46 | } 47 | 48 | @Override 49 | public void saveOptions(Map options) { 50 | if (null != options && !options.isEmpty()) { 51 | options.forEach(this::insertOption); 52 | } 53 | } 54 | 55 | @Override 56 | public List getOptions(){ 57 | return optionDao.selectByExample(new OptionVoExample()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/impl/LogServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service.impl; 2 | 3 | import com.github.pagehelper.PageHelper; 4 | import com.my.blog.website.dao.LogVoMapper; 5 | import com.my.blog.website.service.ILogService; 6 | import com.my.blog.website.utils.DateKit; 7 | import com.my.blog.website.constant.WebConst; 8 | import com.my.blog.website.modal.Vo.LogVo; 9 | import com.my.blog.website.modal.Vo.LogVoExample; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by BlueT on 2017/3/4. 19 | */ 20 | @Service 21 | public class LogServiceImpl implements ILogService { 22 | 23 | private static final Logger LOGGER = LoggerFactory.getLogger(LogServiceImpl.class); 24 | 25 | @Resource 26 | private LogVoMapper logDao; 27 | 28 | @Override 29 | public void insertLog(LogVo logVo) { 30 | logDao.insert(logVo); 31 | } 32 | 33 | @Override 34 | public void insertLog(String action, String data, String ip, Integer authorId) { 35 | LogVo logs = new LogVo(); 36 | logs.setAction(action); 37 | logs.setData(data); 38 | logs.setIp(ip); 39 | logs.setAuthorId(authorId); 40 | logs.setCreated(DateKit.getCurrentUnixTime()); 41 | logDao.insert(logs); 42 | } 43 | 44 | @Override 45 | public List getLogs(int page, int limit) { 46 | LOGGER.debug("Enter getLogs method:page={},linit={}",page,limit); 47 | if (page <= 0) { 48 | page = 1; 49 | } 50 | if (limit < 1 || limit > WebConst.MAX_POSTS) { 51 | limit = 10; 52 | } 53 | LogVoExample logVoExample = new LogVoExample(); 54 | logVoExample.setOrderByClause("id desc"); 55 | PageHelper.startPage((page - 1) * limit, limit); 56 | List logVos = logDao.selectByExample(logVoExample); 57 | LOGGER.debug("Exit getLogs method"); 58 | return logVos; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/page-category.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 |
8 | : 9 |
10 | 11 |
12 |

抱歉,还没有相关文章.

13 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
28 |
发布于
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/db/Column.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup.db; 2 | 3 | public class Column { 4 | private String catalogName; 5 | private String schemaName; 6 | private String tableName; 7 | private String name; 8 | private String label; 9 | private int type; 10 | private String typeName; 11 | private String columnClassName; 12 | private int displaySize; 13 | private int precision; 14 | private int scale; 15 | 16 | public String getName() { 17 | return name; 18 | } 19 | 20 | public String getLabel() { 21 | return label; 22 | } 23 | 24 | public int getType() { 25 | return type; 26 | } 27 | 28 | public void setCatalogName(String catalogName) { 29 | this.catalogName = catalogName; 30 | } 31 | 32 | public void setSchemaName(String schemaName) { 33 | this.schemaName = schemaName; 34 | } 35 | 36 | public void setTableName(String tableName) { 37 | this.tableName = tableName; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | public void setLabel(String label) { 45 | this.label = label; 46 | } 47 | 48 | public void setType(int type) { 49 | this.type = type; 50 | } 51 | 52 | public void setTypeName(String typeName) { 53 | this.typeName = typeName; 54 | } 55 | 56 | public void setColumnClassName(String columnClassName) { 57 | this.columnClassName = columnClassName; 58 | } 59 | 60 | public void setDisplaySize(int displaySize) { 61 | this.displaySize = displaySize; 62 | } 63 | 64 | public void setPrecision(int precision) { 65 | this.precision = precision; 66 | } 67 | 68 | public void setScale(int scale) { 69 | this.scale = scale; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "Column [catalogName=" + catalogName + ", schemaName=" 75 | + schemaName + ", tableName=" + tableName + ", name=" + name 76 | + ", label=" + label + ", type=" + type + ", typeName=" 77 | + typeName + ", columnClassName=" + columnClassName 78 | + ", displaySize=" + displaySize + ", precision=" + precision 79 | + ", scale=" + scale + "]"; 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/impl/AttachServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service.impl; 2 | 3 | import com.github.pagehelper.PageHelper; 4 | import com.github.pagehelper.PageInfo; 5 | import com.my.blog.website.dao.AttachVoMapper; 6 | import com.my.blog.website.utils.DateKit; 7 | import com.my.blog.website.modal.Vo.AttachVo; 8 | import com.my.blog.website.modal.Vo.AttachVoExample; 9 | import com.my.blog.website.service.IAttachService; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by wangq on 2017/3/20. 19 | */ 20 | @Service 21 | public class AttachServiceImpl implements IAttachService { 22 | private static final Logger LOGGER = LoggerFactory.getLogger(AttachServiceImpl.class); 23 | 24 | @Resource 25 | private AttachVoMapper attachDao; 26 | 27 | @Override 28 | public PageInfo getAttachs(Integer page, Integer limit) { 29 | PageHelper.startPage(page, limit); 30 | AttachVoExample attachVoExample = new AttachVoExample(); 31 | attachVoExample.setOrderByClause("id desc"); 32 | List attachVos = attachDao.selectByExample(attachVoExample); 33 | return new PageInfo<>(attachVos); 34 | } 35 | 36 | @Override 37 | public AttachVo selectById(Integer id) { 38 | if(null != id){ 39 | return attachDao.selectByPrimaryKey(id); 40 | } 41 | return null; 42 | } 43 | 44 | @Override 45 | public void save(String fname, String fkey, String ftype, Integer author) { 46 | AttachVo attach = new AttachVo(); 47 | attach.setFname(fname); 48 | attach.setAuthorId(author); 49 | attach.setFkey(fkey); 50 | attach.setFtype(ftype); 51 | attach.setCreated(DateKit.getCurrentUnixTime()); 52 | attachDao.insertSelective(attach); 53 | } 54 | 55 | @Override 56 | public void deleteById(Integer id) { 57 | if (null != id) { 58 | attachDao.deleteByPrimaryKey( id); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/IContentService.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.my.blog.website.modal.Vo.ContentVoExample; 5 | import com.my.blog.website.modal.Vo.ContentVo; 6 | 7 | /** 8 | * Created by Administrator on 2017/3/13 013. 9 | */ 10 | public interface IContentService { 11 | 12 | // /** 13 | // * 保存文章 14 | // * @param contentVo contentVo 15 | // */ 16 | // void insertContent(ContentVo contentVo); 17 | 18 | /** 19 | * 发布文章 20 | * @param contents 21 | */ 22 | void publish(ContentVo contents); 23 | 24 | /** 25 | *查询文章返回多条数据 26 | * @param p 当前页 27 | * @param limit 每页条数 28 | * @return ContentVo 29 | */ 30 | PageInfo getContents(Integer p, Integer limit); 31 | 32 | 33 | /** 34 | * 根据id或slug获取文章 35 | * 36 | * @param id id 37 | * @return ContentVo 38 | */ 39 | ContentVo getContents(String id); 40 | 41 | /** 42 | * 根据主键更新 43 | * @param contentVo contentVo 44 | */ 45 | void updateContentByCid(ContentVo contentVo); 46 | 47 | 48 | /** 49 | * 查询分类/标签下的文章归档 50 | * @param mid mid 51 | * @param page page 52 | * @param limit limit 53 | * @return ContentVo 54 | */ 55 | PageInfo getArticles(Integer mid, int page, int limit); 56 | 57 | /** 58 | * 搜索、分页 59 | * @param keyword keyword 60 | * @param page page 61 | * @param limit limit 62 | * @return ContentVo 63 | */ 64 | PageInfo getArticles(String keyword,Integer page,Integer limit); 65 | 66 | 67 | /** 68 | * @param commentVoExample 69 | * @param page 70 | * @param limit 71 | * @return 72 | */ 73 | PageInfo getArticlesWithpage(ContentVoExample commentVoExample, Integer page, Integer limit); 74 | /** 75 | * 根据文章id删除 76 | * @param cid 77 | */ 78 | void deleteByCid(Integer cid); 79 | 80 | /** 81 | * 编辑文章 82 | * @param contents 83 | */ 84 | void updateArticle(ContentVo contents); 85 | 86 | 87 | /** 88 | * 更新原有文章的category 89 | * @param ordinal 90 | * @param newCatefory 91 | */ 92 | void updateCategory(String ordinal,String newCatefory); 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/backup/db/DataTable.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils.backup.db; 2 | 3 | import java.sql.Connection; 4 | import java.sql.ResultSet; 5 | import java.sql.ResultSetMetaData; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | 9 | public class DataTable extends ArrayList { 10 | /** 11 | * 12 | */ 13 | private static final long serialVersionUID = -3057968190529400383L; 14 | 15 | public static DataTable execute(Connection connection, String query) 16 | throws SQLException { 17 | return parse(connection.prepareStatement(query).executeQuery()); 18 | } 19 | 20 | public static DataTable parse(ResultSet resultSet) throws SQLException { 21 | ResultSetMetaData metaData = resultSet.getMetaData(); 22 | DataTable dataTable = new DataTable(); 23 | dataTable.columns = new ColumnCollection(); 24 | 25 | int colCount = metaData.getColumnCount(); 26 | for (int i = 1; i <= colCount; i++) { 27 | Column column = new Column(); 28 | column.setCatalogName(metaData.getCatalogName(i)); 29 | column.setColumnClassName(metaData.getColumnClassName(i)); 30 | column.setDisplaySize(metaData.getColumnDisplaySize(i)); 31 | column.setLabel(metaData.getColumnLabel(i)); 32 | column.setName(metaData.getColumnName(i)); 33 | column.setPrecision(metaData.getPrecision(i)); 34 | column.setScale(metaData.getScale(i)); 35 | column.setSchemaName(metaData.getSchemaName(i)); 36 | column.setTableName(metaData.getTableName(i)); 37 | column.setType(metaData.getColumnType(i)); 38 | column.setTypeName(metaData.getColumnTypeName(i)); 39 | dataTable.columns.add(column); 40 | } 41 | 42 | while (resultSet.next()) { 43 | Object[] data = new Object[colCount]; 44 | for (int i = 1; i <= data.length; i++) { 45 | data[i - 1] = resultSet.getObject(i); 46 | } 47 | dataTable.add(new Row(dataTable, data)); 48 | } 49 | resultSet.close(); 50 | return dataTable; 51 | } 52 | 53 | private ColumnCollection columns; 54 | 55 | public ColumnCollection getColumns() { 56 | return columns; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | String s = columns.toString() + "\n"; 62 | if (size() == 0) { 63 | s += "Rows is empty\n"; 64 | } else { 65 | s += "Rows : {" + String.valueOf(get(0)); 66 | for (int i = 1; i < size(); i++) { 67 | s += "\n" + String.valueOf(get(i)); 68 | } 69 | s += "}\n"; 70 | } 71 | return s; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/CoreApplication.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website; 2 | 3 | import com.alibaba.druid.pool.DruidDataSource; 4 | import org.apache.ibatis.session.SqlSessionFactory; 5 | import org.mybatis.spring.SqlSessionFactoryBean; 6 | import org.mybatis.spring.annotation.MapperScan; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.boot.builder.SpringApplicationBuilder; 10 | import org.springframework.boot.context.properties.ConfigurationProperties; 11 | import org.springframework.boot.web.support.SpringBootServletInitializer; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 14 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 15 | import org.springframework.transaction.PlatformTransactionManager; 16 | import org.springframework.transaction.annotation.EnableTransactionManagement; 17 | 18 | import javax.sql.DataSource; 19 | 20 | @MapperScan("com.my.blog.website.dao") 21 | @SpringBootApplication 22 | @EnableTransactionManagement 23 | public class CoreApplication extends SpringBootServletInitializer 24 | { 25 | @Override 26 | protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { 27 | return builder.sources(this.getClass()); 28 | } 29 | 30 | @Bean(initMethod = "init", destroyMethod = "close") 31 | @ConfigurationProperties(prefix = "spring.datasource") 32 | public DataSource dataSource() { 33 | return new DruidDataSource(); 34 | } 35 | 36 | @Bean 37 | public SqlSessionFactory sqlSessionFactoryBean() throws Exception { 38 | PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 39 | SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 40 | sqlSessionFactoryBean.setDataSource(dataSource()); 41 | sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath*:/mapper/*Mapper.xml")); 42 | return sqlSessionFactoryBean.getObject(); 43 | } 44 | 45 | @Bean 46 | public PlatformTransactionManager transactionManager() { 47 | return new DataSourceTransactionManager(dataSource()); 48 | } 49 | 50 | 51 | public static void main(String[] args) { 52 | SpringApplication.run(CoreApplication.class, args); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/resources/templates/comm/tale_comment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 60 | 61 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/IPKit.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import java.net.InetAddress; 5 | import java.net.NetworkInterface; 6 | import java.net.SocketException; 7 | import java.util.Enumeration; 8 | 9 | /** 10 | * ip工具类 11 | * Created by BlueT on 2017/3/9. 12 | */ 13 | public class IPKit { 14 | /** 15 | * @param request 请求 16 | * @return IP Address 17 | */ 18 | public static String getIpAddrByRequest(HttpServletRequest request) { 19 | String ip = request.getHeader("x-forwarded-for"); 20 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 21 | ip = request.getHeader("Proxy-Client-IP"); 22 | } 23 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 24 | ip = request.getHeader("WL-Proxy-Client-IP"); 25 | } 26 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 27 | ip = request.getRemoteAddr(); 28 | } 29 | return ip; 30 | } 31 | 32 | /** 33 | * @return 本机IPSocketException 34 | * @throws SocketException 35 | */ 36 | public static String getRealIp() throws SocketException { 37 | String localip = null;// 本地IP,如果没有配置外网IP则返回它 38 | String netip = null;// 外网IP 39 | 40 | Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces(); 41 | InetAddress ip = null; 42 | boolean finded = false;// 是否找到外网IP 43 | while (netInterfaces.hasMoreElements() && !finded) { 44 | NetworkInterface ni = netInterfaces.nextElement(); 45 | Enumeration address = ni.getInetAddresses(); 46 | while (address.hasMoreElements()) { 47 | ip = address.nextElement(); 48 | if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !ip.getHostAddress().contains(":")) {// 外网IP 49 | netip = ip.getHostAddress(); 50 | finded = true; 51 | break; 52 | } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && !ip.getHostAddress().contains(":")) {// 内网IP 53 | localip = ip.getHostAddress(); 54 | } 55 | } 56 | } 57 | 58 | if (netip != null && !"".equals(netip)) { 59 | return netip; 60 | } else { 61 | return localip; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/ZipUtils.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.util.zip.ZipEntry; 7 | import java.util.zip.ZipOutputStream; 8 | 9 | /** 10 | * zip压缩工具类 11 | */ 12 | public class ZipUtils { 13 | 14 | public static void zipFolder(String srcFolder, String destZipFile) throws Exception { 15 | ZipOutputStream zip = null; 16 | FileOutputStream fileWriter = null; 17 | 18 | fileWriter = new FileOutputStream(destZipFile); 19 | zip = new ZipOutputStream(fileWriter); 20 | 21 | addFolderToZip("", srcFolder, zip); 22 | zip.flush(); 23 | zip.close(); 24 | } 25 | 26 | public static void zipFile(String filePath, String zipPath) throws Exception{ 27 | byte[] buffer = new byte[1024]; 28 | FileOutputStream fos = new FileOutputStream(zipPath); 29 | ZipOutputStream zos = new ZipOutputStream(fos); 30 | ZipEntry ze= new ZipEntry("spy.log"); 31 | zos.putNextEntry(ze); 32 | FileInputStream in = new FileInputStream(filePath); 33 | int len; 34 | while ((len = in.read(buffer)) > 0) { 35 | zos.write(buffer, 0, len); 36 | } 37 | in.close(); 38 | zos.closeEntry(); 39 | //remember close it 40 | zos.close(); 41 | } 42 | 43 | public static void addFileToZip(String path, String srcFile, ZipOutputStream zip) 44 | throws Exception { 45 | 46 | File folder = new File(srcFile); 47 | if (folder.isDirectory()) { 48 | addFolderToZip(path, srcFile, zip); 49 | } else { 50 | byte[] buf = new byte[1024]; 51 | int len; 52 | FileInputStream in = new FileInputStream(srcFile); 53 | zip.putNextEntry(new ZipEntry(path + "/" + folder.getName())); 54 | while ((len = in.read(buf)) > 0) { 55 | zip.write(buf, 0, len); 56 | } 57 | } 58 | } 59 | 60 | public static void addFolderToZip(String path, String srcFolder, ZipOutputStream zip) throws Exception { 61 | File folder = new File(srcFolder); 62 | if (null != path && folder.isDirectory()) { 63 | for (String fileName : folder.list()) { 64 | if (path.equals("")) { 65 | addFileToZip(folder.getName(), srcFolder + "/" + fileName, zip); 66 | } else { 67 | addFileToZip(path + "/" + folder.getName(), srcFolder + "/" + fileName, zip); 68 | } 69 | } 70 | } 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /src/main/resources/static/admin/css/multi-select.css: -------------------------------------------------------------------------------- 1 | .ms-container{ 2 | background: transparent url('../img/switch.png') no-repeat 50% 50%; 3 | width: 370px; 4 | } 5 | 6 | .ms-container:after{ 7 | content: "."; 8 | display: block; 9 | height: 0; 10 | line-height: 0; 11 | font-size: 0; 12 | clear: both; 13 | min-height: 0; 14 | visibility: hidden; 15 | } 16 | 17 | .ms-container .ms-selectable, .ms-container .ms-selection{ 18 | background: #fff; 19 | color: #555555; 20 | float: left; 21 | width: 45%; 22 | } 23 | .ms-container .ms-selection{ 24 | float: right; 25 | } 26 | 27 | .ms-container .ms-list{ 28 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 29 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 30 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 31 | -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; 32 | -moz-transition: border linear 0.2s, box-shadow linear 0.2s; 33 | -ms-transition: border linear 0.2s, box-shadow linear 0.2s; 34 | -o-transition: border linear 0.2s, box-shadow linear 0.2s; 35 | transition: border linear 0.2s, box-shadow linear 0.2s; 36 | border: 1px solid #ccc; 37 | -webkit-border-radius: 3px; 38 | -moz-border-radius: 3px; 39 | border-radius: 3px; 40 | position: relative; 41 | height: 200px; 42 | padding: 0; 43 | overflow-y: auto; 44 | } 45 | 46 | .ms-container .ms-list.ms-focus{ 47 | border-color: rgba(82, 168, 236, 0.8); 48 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 49 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 50 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 51 | outline: 0; 52 | outline: thin dotted \9; 53 | } 54 | 55 | .ms-container ul{ 56 | margin: 0; 57 | list-style-type: none; 58 | padding: 0; 59 | } 60 | 61 | .ms-container .ms-optgroup-container{ 62 | width: 100%; 63 | } 64 | 65 | .ms-container .ms-optgroup-label{ 66 | margin: 0; 67 | padding: 5px 0px 0px 5px; 68 | cursor: pointer; 69 | color: #999; 70 | } 71 | 72 | .ms-container .ms-selectable li.ms-elem-selectable, 73 | .ms-container .ms-selection li.ms-elem-selection{ 74 | border-bottom: 1px #eee solid; 75 | padding: 2px 10px; 76 | color: #555; 77 | font-size: 14px; 78 | } 79 | 80 | .ms-container .ms-selectable li.ms-hover, 81 | .ms-container .ms-selection li.ms-hover{ 82 | cursor: pointer; 83 | color: #fff; 84 | text-decoration: none; 85 | background-color: #08c; 86 | } 87 | 88 | .ms-container .ms-selectable li.disabled, 89 | .ms-container .ms-selection li.disabled{ 90 | background-color: #eee; 91 | color: #aaa; 92 | cursor: text; 93 | } -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/toggles.min.js: -------------------------------------------------------------------------------- 1 | (function($){/* 2 | jQuery Toggles v2.0.4 3 | Copyright 2013 Simon Tabor - MIT License 4 | https://github.com/simontabor/jquery-toggles / http://simontabor.com/labs/toggles 5 | */ 6 | $.fn.toggles=function(d){function p(e,b,f,c){var r=e.toggleClass("active").hasClass("active");if(c!==r){var d=e.find(".toggle-inner").css(w);e.find(".toggle-off").toggleClass("active");e.find(".toggle-on").toggleClass("active");a.checkbox.prop("checked",r);if(!k){var l=r?0:-b+f;d.css("margin-left",l);setTimeout(function(){d.css(x);d.css("margin-left",l)},a.animate)}}}d=d||{};var a=$.extend({drag:!0,click:!0,text:{on:"ON",off:"OFF"},on:!1,animate:250,transition:"ease-in-out",checkbox:null,clicker:null, 7 | width:50,height:20,type:"compact"},d),k="select"==a.type;a.checkbox=$(a.checkbox);a.clicker&&(a.clicker=$(a.clicker));d="margin-left "+a.animate+"ms "+a.transition;var w={"-webkit-transition":d,"-moz-transition":d,transition:d},x={"-webkit-transition":"","-moz-transition":"",transition:""};return this.each(function(){var e=$(this),b=e.height(),f=e.width();if(!b||!f)e.height(b=a.height),e.width(f=a.width);var c=$('
'),d=$('
'),t=$('
'), 8 | l=$('
'),h=$('
'),m=b/2,s=f-m;t.css({height:b,width:s,textAlign:"center",textIndent:k?"":-m,lineHeight:b+"px"}).html(a.text.on);l.css({height:b,width:s,marginLeft:k?"":-m,textAlign:"center",textIndent:k?"":m,lineHeight:b+"px"}).html(a.text.off).addClass("active");h.css({height:b,width:b,marginLeft:-m});d.css({width:2*f-b,marginLeft:k?0:-f+b});k&&(c.addClass("toggle-select"),e.css("width",2*s),h.hide());e.html(c.html(d.append(t,h,l)));c.on("toggle",function(a, 9 | d){a&&a.stopPropagation();p(c,f,b);e.trigger("toggle",!d)});e.on("toggleOn",function(){p(c,f,b,!1)});e.on("toggleOff",function(){p(c,f,b,!0)});a.on&&p(c,f,b);if(a.click&&(!a.clicker||!a.clicker.has(e).length))e.on("click",function(b){(b.target!=h[0]||!a.drag)&&c.trigger("toggle",c.hasClass("active"))});if(a.clicker)a.clicker.on("click",function(b){(b.target!=h[0]||!a.drag)&&c.trigger("toggle",c.hasClass("active"))});if(a.drag&&!k){var g,u=(f-b)/4,v=function(k){e.off("mousemove");c.off("mouseleave"); 10 | h.off("mouseup");var q=c.hasClass("active");!g&&a.click&&"mouseleave"!==k.type?c.trigger("toggle",q):q?g<-u?c.trigger("toggle",q):d.animate({marginLeft:0},a.animate/2):g>u?c.trigger("toggle",q):d.animate({marginLeft:-f+b},a.animate/2)},n=-f+b;h.on("mousedown",function(a){g=0;h.off("mouseup");c.off("mouseleave");var b=a.pageX;e.on("mousemove",h,function(a){g=a.pageX-b;c.hasClass("active")?(a=g,0g&&(a=n),g>-n&&(a=0));d.css("margin-left",a)});h.on("mouseup",v);c.on("mouseleave", 11 | v)})}})};})(jQuery); 12 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/impl/RelationshipServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service.impl; 2 | 3 | import com.my.blog.website.modal.Vo.RelationshipVoExample; 4 | import com.my.blog.website.modal.Vo.RelationshipVoKey; 5 | import com.my.blog.website.service.IRelationshipService; 6 | import com.my.blog.website.dao.RelationshipVoMapper; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Service; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by BlueT on 2017/3/18. 16 | */ 17 | @Service 18 | public class RelationshipServiceImpl implements IRelationshipService { 19 | private static final Logger LOGGER = LoggerFactory.getLogger(RelationshipServiceImpl.class); 20 | 21 | @Resource 22 | private RelationshipVoMapper relationshipVoMapper; 23 | 24 | @Override 25 | public void deleteById(Integer cid, Integer mid) { 26 | RelationshipVoExample relationshipVoExample = new RelationshipVoExample(); 27 | RelationshipVoExample.Criteria criteria = relationshipVoExample.createCriteria(); 28 | if (cid != null) { 29 | criteria.andCidEqualTo(cid); 30 | } 31 | if (mid != null) { 32 | criteria.andMidEqualTo(mid); 33 | } 34 | relationshipVoMapper.deleteByExample(relationshipVoExample); 35 | } 36 | 37 | @Override 38 | public List getRelationshipById(Integer cid, Integer mid) { 39 | RelationshipVoExample relationshipVoExample = new RelationshipVoExample(); 40 | RelationshipVoExample.Criteria criteria = relationshipVoExample.createCriteria(); 41 | if (cid != null) { 42 | criteria.andCidEqualTo(cid); 43 | } 44 | if (mid != null) { 45 | criteria.andMidEqualTo(mid); 46 | } 47 | return relationshipVoMapper.selectByExample(relationshipVoExample); 48 | } 49 | 50 | @Override 51 | public void insertVo(RelationshipVoKey relationshipVoKey) { 52 | relationshipVoMapper.insert(relationshipVoKey); 53 | } 54 | 55 | @Override 56 | public Long countById(Integer cid, Integer mid) { 57 | LOGGER.debug("Enter countById method:cid={},mid={}",cid,mid); 58 | RelationshipVoExample relationshipVoExample = new RelationshipVoExample(); 59 | RelationshipVoExample.Criteria criteria = relationshipVoExample.createCriteria(); 60 | if (cid != null) { 61 | criteria.andCidEqualTo(cid); 62 | } 63 | if (mid != null) { 64 | criteria.andMidEqualTo(mid); 65 | } 66 | long num = relationshipVoMapper.countByExample(relationshipVoExample); 67 | LOGGER.debug("Exit countById method return num={}",num); 68 | return num; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/my/blog/website/AsyncTest.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.scheduling.annotation.Async; 8 | import org.springframework.scheduling.annotation.AsyncResult; 9 | import org.springframework.scheduling.annotation.EnableAsync; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | 13 | import java.util.Random; 14 | import java.util.concurrent.Future; 15 | 16 | /** 17 | * 测试异步调用 18 | * Created by Administrator on 2017/3/6 006. 19 | */ 20 | @RunWith(SpringRunner.class) 21 | @SpringBootTest 22 | @EnableAsync 23 | public class AsyncTest { 24 | 25 | @Autowired 26 | private Task task; 27 | 28 | @Test 29 | public void Test() throws Exception { 30 | 31 | long start = System.currentTimeMillis(); 32 | Future task1 = task.doTaskOne(); 33 | Future task2 = task.doTaskTwo(); 34 | Future task3 = task.doTaskThree(); 35 | while(true) { 36 | 37 | if(task1.isDone() && task2.isDone() && task3.isDone()) { 38 | // 三个任务都调用完成,退出循环等待 39 | break; 40 | } 41 | Thread.sleep(1000); 42 | } 43 | long end = System.currentTimeMillis(); 44 | System.out.println("任务全部完成,总耗时:" + (end - start) + "毫秒"); 45 | } 46 | 47 | 48 | 49 | } 50 | 51 | @Component 52 | class Task{ 53 | 54 | private static Random random =new Random(); 55 | 56 | @Async 57 | Future doTaskOne() throws Exception { 58 | System.out.println("开始做任务一"); 59 | long start = System.currentTimeMillis(); 60 | Thread.sleep(random.nextInt(10000)); 61 | long end = System.currentTimeMillis(); 62 | System.out.println("完成任务一,耗时:" + (end - start) + "毫秒"); 63 | return new AsyncResult<>("任务一OK"); 64 | } 65 | 66 | @Async 67 | Future doTaskTwo() throws Exception { 68 | System.out.println("开始做任务二"); 69 | long start = System.currentTimeMillis(); 70 | Thread.sleep(random.nextInt(10000)); 71 | long end = System.currentTimeMillis(); 72 | System.out.println("完成任务二,耗时:" + (end - start) + "毫秒"); 73 | return new AsyncResult<>("任务二OK"); 74 | } 75 | 76 | @Async 77 | Future doTaskThree() throws Exception { 78 | System.out.println("开始做任务三"); 79 | long start = System.currentTimeMillis(); 80 | Thread.sleep(random.nextInt(10000)); 81 | long end = System.currentTimeMillis(); 82 | System.out.println("完成任务三,耗时:" + (end - start) + "毫秒"); 83 | return new AsyncResult<>("任务三OK"); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.service.impl; 2 | 3 | import com.my.blog.website.dao.UserVoMapper; 4 | import com.my.blog.website.exception.TipException; 5 | import com.my.blog.website.modal.Vo.UserVo; 6 | import com.my.blog.website.service.IUserService; 7 | import com.my.blog.website.utils.TaleUtils; 8 | import com.my.blog.website.modal.Vo.UserVoExample; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by BlueT on 2017/3/3. 19 | */ 20 | @Service 21 | public class UserServiceImpl implements IUserService { 22 | private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class); 23 | 24 | @Resource 25 | private UserVoMapper userDao; 26 | 27 | @Override 28 | public Integer insertUser(UserVo userVo) { 29 | Integer uid = null; 30 | if (StringUtils.isNotBlank(userVo.getUsername()) && StringUtils.isNotBlank(userVo.getEmail())) { 31 | // 用户密码加密 32 | String encodePwd = TaleUtils.MD5encode(userVo.getUsername() + userVo.getPassword()); 33 | userVo.setPassword(encodePwd); 34 | userDao.insertSelective(userVo); 35 | } 36 | return userVo.getUid(); 37 | } 38 | 39 | @Override 40 | public UserVo queryUserById(Integer uid) { 41 | UserVo userVo = null; 42 | if (uid != null) { 43 | userVo = userDao.selectByPrimaryKey(uid); 44 | } 45 | return userVo; 46 | } 47 | 48 | @Override 49 | public UserVo login(String username, String password) { 50 | if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) { 51 | throw new TipException("用户名和密码不能为空"); 52 | } 53 | UserVoExample example = new UserVoExample(); 54 | UserVoExample.Criteria criteria = example.createCriteria(); 55 | criteria.andUsernameEqualTo(username); 56 | long count = userDao.countByExample(example); 57 | if (count < 1) { 58 | throw new TipException("不存在该用户"); 59 | } 60 | String pwd = TaleUtils.MD5encode(username+password); 61 | criteria.andPasswordEqualTo(pwd); 62 | List userVos = userDao.selectByExample(example); 63 | if (userVos.size()!=1) { 64 | throw new TipException("用户名或密码错误"); 65 | } 66 | return userVos.get(0); 67 | } 68 | 69 | @Override 70 | public void updateByUid(UserVo userVo) { 71 | if (null == userVo || null == userVo.getUid()) { 72 | throw new TipException("userVo is null"); 73 | } 74 | int i = userDao.updateByPrimaryKeySelective(userVo); 75 | if(i!=1){ 76 | throw new TipException("update user by uid and retrun is not one"); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/UserVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class UserVo implements Serializable { 9 | /** 10 | * user表主键 11 | */ 12 | private Integer uid; 13 | 14 | /** 15 | * 用户名称 16 | */ 17 | private String username; 18 | 19 | /** 20 | * 用户密码 21 | */ 22 | private String password; 23 | 24 | /** 25 | * 用户的邮箱 26 | */ 27 | private String email; 28 | 29 | /** 30 | * 用户的主页 31 | */ 32 | private String homeUrl; 33 | 34 | /** 35 | * 用户显示的名称 36 | */ 37 | private String screenName; 38 | 39 | /** 40 | * 用户注册时的GMT unix时间戳 41 | */ 42 | private Integer created; 43 | 44 | /** 45 | * 最后活动时间 46 | */ 47 | private Integer activated; 48 | 49 | /** 50 | * 上次登录最后活跃时间 51 | */ 52 | private Integer logged; 53 | 54 | /** 55 | * 用户组 56 | */ 57 | private String groupName; 58 | 59 | private static final long serialVersionUID = 1L; 60 | 61 | public Integer getUid() { 62 | return uid; 63 | } 64 | 65 | public void setUid(Integer uid) { 66 | this.uid = uid; 67 | } 68 | 69 | public String getUsername() { 70 | return username; 71 | } 72 | 73 | public void setUsername(String username) { 74 | this.username = username; 75 | } 76 | 77 | public String getPassword() { 78 | return password; 79 | } 80 | 81 | public void setPassword(String password) { 82 | this.password = password; 83 | } 84 | 85 | public String getEmail() { 86 | return email; 87 | } 88 | 89 | public void setEmail(String email) { 90 | this.email = email; 91 | } 92 | 93 | public String getHomeUrl() { 94 | return homeUrl; 95 | } 96 | 97 | public void setHomeUrl(String homeUrl) { 98 | this.homeUrl = homeUrl; 99 | } 100 | 101 | public String getScreenName() { 102 | return screenName; 103 | } 104 | 105 | public void setScreenName(String screenName) { 106 | this.screenName = screenName; 107 | } 108 | 109 | public Integer getCreated() { 110 | return created; 111 | } 112 | 113 | public void setCreated(Integer created) { 114 | this.created = created; 115 | } 116 | 117 | public Integer getActivated() { 118 | return activated; 119 | } 120 | 121 | public void setActivated(Integer activated) { 122 | this.activated = activated; 123 | } 124 | 125 | public Integer getLogged() { 126 | return logged; 127 | } 128 | 129 | public void setLogged(Integer logged) { 130 | this.logged = logged; 131 | } 132 | 133 | public String getGroupName() { 134 | return groupName; 135 | } 136 | 137 | public void setGroupName(String groupName) { 138 | this.groupName = groupName; 139 | } 140 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/controller/admin/CategoryController.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller.admin; 2 | 3 | import com.my.blog.website.constant.WebConst; 4 | import com.my.blog.website.controller.BaseController; 5 | import com.my.blog.website.dto.MetaDto; 6 | import com.my.blog.website.dto.Types; 7 | import com.my.blog.website.exception.TipException; 8 | import com.my.blog.website.modal.Bo.RestResponseBo; 9 | import com.my.blog.website.service.IMetaService; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.stereotype.Controller; 13 | import org.springframework.transaction.annotation.Transactional; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | import javax.annotation.Resource; 17 | import javax.servlet.http.HttpServletRequest; 18 | import java.util.List; 19 | 20 | /** 21 | * Created by 13 on 2017/2/21. 22 | */ 23 | @Controller 24 | @RequestMapping("admin/category") 25 | public class CategoryController extends BaseController { 26 | 27 | private static final Logger LOGGER = LoggerFactory.getLogger(CategoryController.class); 28 | 29 | @Resource 30 | private IMetaService metasService; 31 | 32 | /** 33 | * 分类页 34 | * @param request 35 | * @return 36 | */ 37 | @GetMapping(value = "") 38 | public String index(HttpServletRequest request) { 39 | List categories = metasService.getMetaList(Types.CATEGORY.getType(), null, WebConst.MAX_POSTS); 40 | List tags = metasService.getMetaList(Types.TAG.getType(), null, WebConst.MAX_POSTS); 41 | request.setAttribute("categories", categories); 42 | request.setAttribute("tags", tags); 43 | return "admin/category"; 44 | } 45 | 46 | @PostMapping(value = "save") 47 | @ResponseBody 48 | @Transactional(rollbackFor = TipException.class) 49 | public RestResponseBo saveCategory(@RequestParam String cname, @RequestParam Integer mid) { 50 | try { 51 | metasService.saveMeta(Types.CATEGORY.getType(),cname,mid); 52 | } catch (Exception e) { 53 | String msg = "分类保存失败"; 54 | if (e instanceof TipException) { 55 | msg = e.getMessage(); 56 | } else { 57 | LOGGER.error(msg, e); 58 | } 59 | return RestResponseBo.fail(msg); 60 | } 61 | return RestResponseBo.ok(); 62 | } 63 | 64 | /** 65 | * 删除分类 66 | * @param mid 67 | * @return 68 | */ 69 | @RequestMapping(value = "delete") 70 | @ResponseBody 71 | @Transactional(rollbackFor = TipException.class) 72 | public RestResponseBo delete(@RequestParam int mid) { 73 | try { 74 | metasService.delete(mid); 75 | } catch (Exception e) { 76 | String msg = "删除失败"; 77 | if (e instanceof TipException) { 78 | msg = e.getMessage(); 79 | } else { 80 | LOGGER.error(msg, e); 81 | } 82 | return RestResponseBo.fail(msg); 83 | } 84 | return RestResponseBo.ok(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/resources/templates/themes/default/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <th:block th:text="${title ?: '首页'}+' - '+${commons.site_option('site_title','My Blog')}"></th:block> 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | 30 | 59 | 60 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ./logs 11 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/interceptor/BaseInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.interceptor; 2 | 3 | import com.my.blog.website.modal.Vo.UserVo; 4 | import com.my.blog.website.service.IUserService; 5 | import com.my.blog.website.utils.*; 6 | import com.my.blog.website.constant.WebConst; 7 | import com.my.blog.website.dto.Types; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.servlet.HandlerInterceptor; 12 | import org.springframework.web.servlet.ModelAndView; 13 | 14 | import javax.annotation.Resource; 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.servlet.http.HttpServletResponse; 17 | 18 | /** 19 | * 自定义拦截器 20 | * Created by BlueT on 2017/3/9. 21 | */ 22 | @Component 23 | public class BaseInterceptor implements HandlerInterceptor { 24 | private static final Logger LOGGE = LoggerFactory.getLogger(BaseInterceptor.class); 25 | private static final String USER_AGENT = "user-agent"; 26 | 27 | @Resource 28 | private IUserService userService; 29 | 30 | private MapCache cache = MapCache.single(); 31 | 32 | @Resource 33 | private Commons commons; 34 | 35 | @Resource 36 | private AdminCommons adminCommons; 37 | 38 | 39 | @Override 40 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception { 41 | String uri = request.getRequestURI(); 42 | 43 | LOGGE.info("UserAgent: {}", request.getHeader(USER_AGENT)); 44 | LOGGE.info("用户访问地址: {}, 来路地址: {}", uri, IPKit.getIpAddrByRequest(request)); 45 | 46 | 47 | //请求拦截处理 48 | UserVo user = TaleUtils.getLoginUser(request); 49 | if (null == user) { 50 | Integer uid = TaleUtils.getCookieUid(request); 51 | if (null != uid) { 52 | //这里还是有安全隐患,cookie是可以伪造的 53 | user = userService.queryUserById(uid); 54 | request.getSession().setAttribute(WebConst.LOGIN_SESSION_KEY, user); 55 | } 56 | } 57 | if (uri.startsWith("/admin") && !uri.startsWith("/admin/login") && null == user) { 58 | response.sendRedirect(request.getContextPath() + "/admin/login"); 59 | return false; 60 | } 61 | //设置get请求的token 62 | if (request.getMethod().equals("GET")) { 63 | String csrf_token = UUID.UU64(); 64 | // 默认存储30分钟 65 | cache.hset(Types.CSRF_TOKEN.getType(), csrf_token, uri, 30 * 60); 66 | request.setAttribute("_csrf_token", csrf_token); 67 | } 68 | return true; 69 | } 70 | 71 | @Override 72 | public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { 73 | httpServletRequest.setAttribute("commons", commons);//一些工具类和公共方法 74 | httpServletRequest.setAttribute("adminCommons", adminCommons); 75 | } 76 | 77 | @Override 78 | public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/Tools.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | import sun.misc.BASE64Decoder; 4 | import sun.misc.BASE64Encoder; 5 | 6 | import javax.crypto.Cipher; 7 | import javax.crypto.spec.SecretKeySpec; 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.io.FileOutputStream; 11 | import java.io.IOException; 12 | import java.nio.channels.FileChannel; 13 | import java.util.Random; 14 | 15 | /** 16 | * 工具类 17 | * Created by BlueT on 2017/3/9. 18 | */ 19 | public class Tools { 20 | private static final Random random = new Random(); 21 | 22 | public static void copyFileUsingFileChannels(File source, File dest) throws IOException { 23 | FileChannel inputChannel = null; 24 | FileChannel outputChannel = null; 25 | try { 26 | inputChannel = new FileInputStream(source).getChannel(); 27 | outputChannel = new FileOutputStream(dest).getChannel(); 28 | outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); 29 | } finally { 30 | assert inputChannel != null; 31 | inputChannel.close(); 32 | assert outputChannel != null; 33 | outputChannel.close(); 34 | } 35 | } 36 | 37 | public static int rand(int min, int max) { 38 | return random.nextInt(max) % (max - min + 1) + min; 39 | } 40 | 41 | public static String flowAutoShow(int value) { 42 | int kb = 1024; 43 | int mb = 1048576; 44 | int gb = 1073741824; 45 | if (Math.abs(value) > gb) { 46 | return Math.round(value / gb) + "GB"; 47 | } else if (Math.abs(value) > mb) { 48 | return Math.round(value / mb) + "MB"; 49 | } else if (Math.abs(value) > kb) { 50 | return Math.round(value / kb) + "KB"; 51 | } 52 | return Math.round(value) + ""; 53 | } 54 | 55 | public static String enAes(String data, String key) throws Exception { 56 | Cipher cipher = Cipher.getInstance("AES"); 57 | SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 58 | cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 59 | byte[] encryptedBytes = cipher.doFinal(data.getBytes()); 60 | return new BASE64Encoder().encode(encryptedBytes); 61 | } 62 | 63 | public static String deAes(String data, String key) throws Exception { 64 | Cipher cipher = Cipher.getInstance("AES"); 65 | SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 66 | cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 67 | byte[] cipherTextBytes = new BASE64Decoder().decodeBuffer(data); 68 | byte[] decValue = cipher.doFinal(cipherTextBytes); 69 | return new String(decValue); 70 | } 71 | 72 | /** 73 | * 判断字符串是否为数字和有正确的值 74 | * 75 | * @param str 76 | * @return 77 | */ 78 | public static boolean isNumber(String str) { 79 | // Pattern pattern=Pattern.compile("[0-9]*"); 80 | // return pattern.matcher(str).matches(); 81 | if (null != str && 0 != str.trim().length() && str.matches("\\d*")) { 82 | return true; 83 | } 84 | 85 | return false; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/article.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 13 on 2017/2/22. 3 | */ 4 | // Tags Input 5 | $('#tags').tagsInput({ 6 | width: '100%', 7 | height: '35px', 8 | defaultText: '请输入文章标签' 9 | }); 10 | 11 | $('.toggle').toggles({ 12 | on: true, 13 | text: { 14 | on: '开启', 15 | off: '关闭' 16 | } 17 | }); 18 | 19 | $(".select2").select2({ 20 | width: '100%' 21 | }); 22 | 23 | var tale = new $.tale(); 24 | 25 | /** 26 | * 保存文章 27 | * @param status 28 | */ 29 | function subArticle(status) { 30 | var title = $('#articleForm input[name=title]').val(); 31 | var content = $('#text').val(); 32 | if (title == '') { 33 | tale.alertWarn('请输入文章标题'); 34 | return; 35 | } 36 | if (content == '') { 37 | tale.alertWarn('请输入文章内容'); 38 | return; 39 | } 40 | $('#content-editor').val(content); 41 | $("#articleForm #status").val(status); 42 | $("#articleForm #categories").val($('#multiple-sel').val()); 43 | var params = $("#articleForm").serialize(); 44 | var url = $('#articleForm #cid').val() != '' ? '/admin/article/modify' : '/admin/article/publish'; 45 | tale.post({ 46 | url:url, 47 | data:params, 48 | success: function (result) { 49 | if (result && result.success) { 50 | tale.alertOk({ 51 | text:'文章保存成功', 52 | then: function () { 53 | setTimeout(function () { 54 | window.location.href = '/admin/article'; 55 | }, 500); 56 | } 57 | }); 58 | } else { 59 | tale.alertError(result.msg || '保存文章失败'); 60 | } 61 | } 62 | }); 63 | } 64 | 65 | var textarea = $('#text'), 66 | toolbar = $('
').insertBefore(textarea.parent()) 67 | preview = $('
').insertAfter('.markdown-editor'); 68 | 69 | markdown(textarea, toolbar, preview); 70 | 71 | 72 | function allow_comment(obj) { 73 | var this_ = $(obj); 74 | var on = this_.find('.toggle-on.active').length; 75 | var off = this_.find('.toggle-off.active').length; 76 | if (on == 1) { 77 | $('#allow_comment').val(false); 78 | } 79 | if (off == 1) { 80 | $('#allow_comment').val(true); 81 | } 82 | } 83 | 84 | function allow_ping(obj) { 85 | var this_ = $(obj); 86 | var on = this_.find('.toggle-on.active').length; 87 | var off = this_.find('.toggle-off.active').length; 88 | if (on == 1) { 89 | $('#allow_ping').val(false); 90 | } 91 | if (off == 1) { 92 | $('#allow_ping').val(true); 93 | } 94 | } 95 | 96 | 97 | function allow_feed(obj) { 98 | var this_ = $(obj); 99 | var on = this_.find('.toggle-on.active').length; 100 | var off = this_.find('.toggle-off.active').length; 101 | if (on == 1) { 102 | $('#allow_feed').val(false); 103 | } 104 | if (off == 1) { 105 | $('#allow_feed').val(true); 106 | } 107 | } 108 | 109 | $('div.allow-false').toggles({ 110 | off: true, 111 | text: { 112 | on: '开启', 113 | off: '关闭' 114 | } 115 | }); -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/controller/admin/LinksController.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller.admin; 2 | 3 | import com.my.blog.website.controller.BaseController; 4 | import com.my.blog.website.exception.TipException; 5 | import com.my.blog.website.modal.Bo.RestResponseBo; 6 | import com.my.blog.website.service.IMetaService; 7 | import com.my.blog.website.dto.Types; 8 | import com.my.blog.website.modal.Vo.MetaVo; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.transaction.annotation.Transactional; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import javax.annotation.Resource; 16 | import javax.servlet.http.HttpServletRequest; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by 13 on 2017/2/21. 21 | */ 22 | @Controller 23 | @RequestMapping("admin/links") 24 | public class LinksController extends BaseController { 25 | 26 | private static final Logger LOGGER = LoggerFactory.getLogger(LinksController.class); 27 | 28 | @Resource 29 | private IMetaService metasService; 30 | 31 | /** 32 | * 友链 33 | * @param request 34 | * @return 35 | */ 36 | @GetMapping(value = "") 37 | public String index(HttpServletRequest request) { 38 | List metas = metasService.getMetas(Types.LINK.getType()); 39 | request.setAttribute("links", metas); 40 | return "admin/links"; 41 | } 42 | 43 | @PostMapping(value = "save") 44 | @ResponseBody 45 | @Transactional(rollbackFor = TipException.class) 46 | public RestResponseBo saveLink(@RequestParam String title, @RequestParam String url, 47 | @RequestParam String logo, @RequestParam Integer mid, 48 | @RequestParam(value = "sort", defaultValue = "0") int sort) { 49 | try { 50 | MetaVo metas = new MetaVo(); 51 | metas.setName(title); 52 | metas.setSlug(url); 53 | metas.setDescription(logo); 54 | metas.setSort(sort); 55 | metas.setType(Types.LINK.getType()); 56 | if (null != mid) { 57 | metas.setMid(mid); 58 | metasService.update(metas); 59 | } else { 60 | metasService.saveMeta(metas); 61 | } 62 | } catch (Exception e) { 63 | String msg = "友链保存失败"; 64 | if (e instanceof TipException) { 65 | msg = e.getMessage(); 66 | } else { 67 | LOGGER.error(msg, e); 68 | } 69 | return RestResponseBo.fail(msg); 70 | } 71 | return RestResponseBo.ok(); 72 | } 73 | 74 | @RequestMapping(value = "delete") 75 | @ResponseBody 76 | @Transactional(rollbackFor = TipException.class) 77 | public RestResponseBo delete(@RequestParam int mid) { 78 | try { 79 | metasService.delete(mid); 80 | } catch (Exception e) { 81 | String msg = "友链删除失败"; 82 | if (e instanceof TipException) { 83 | msg = e.getMessage(); 84 | } else { 85 | LOGGER.error(msg, e); 86 | } 87 | return RestResponseBo.fail(msg); 88 | } 89 | return RestResponseBo.ok(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/html5.min.js: -------------------------------------------------------------------------------- 1 | (function(e,t){function n(e,t){var n=e.createElement("p"),i=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x",i.insertBefore(n.lastChild,i.firstChild)}function i(){var e=m.elements;return"string"==typeof e?e.split(" "):e}function r(e){var t={},n=e.createElement,r=e.createDocumentFragment,o=r();e.createElement=function(e){m.shivMethods||n(e);var i;return i=t[e]?t[e].cloneNode():g.test(e)?(t[e]=n(e)).cloneNode():n(e),i.canHaveChildren&&!f.test(e)?o.appendChild(i):i},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+i().join().replace(/\w+/g,function(e){return t[e]=n(e),o.createElement(e),'c("'+e+'")'})+");return n}")(m,o)}function o(e){var t;return e.documentShived?e:(m.shivCSS&&!d&&(t=!!n(e,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),h||(t=!r(e)),t&&(e.documentShived=t),e)}function a(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+i().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(s(t)));return a}function s(e){for(var t,n=e.attributes,i=n.length,r=e.ownerDocument.createElement(b+":"+e.nodeName);i--;)t=n[i],t.specified&&r.setAttribute(t.nodeName,t.nodeValue);return r.style.cssText=e.style.cssText,r}function l(e){for(var t,n=e.split("{"),r=n.length,o=RegExp("(^|[\\s,>+~])("+i().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+b+"\\:$2";r--;)t=n[r]=n[r].split("}"),t[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}function c(e){for(var t=e.length;t--;)e[t].removeNode()}function u(e){var t,i,r=e.namespaces,o=e.parentWindow;return!y||e.printShived?e:(r[b]===void 0&&r.add(b),o.attachEvent("onbeforeprint",function(){for(var r,o,s,c=e.styleSheets,u=[],d=c.length,h=Array(d);d--;)h[d]=c[d];for(;s=h.pop();)if(!s.disabled&&v.test(s.media)){for(r=s.imports,d=0,o=r.length;o>d;d++)h.push(r[d]);try{u.push(s.cssText)}catch(p){}}u=l(u.reverse().join("")),i=a(e),t=n(e,u)}),o.attachEvent("onafterprint",function(){c(i),t.removeNode(!0)}),e.printShived=!0,e)}var d,h,p=e.html5||{},f=/^<|^(?:button|form|map|select|textarea|object|iframe)$/i,g=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i;(function(){var n=t.createElement("a");n.innerHTML="",d="hidden"in n,d&&"function"==typeof injectElementWithStyles&&injectElementWithStyles("#modernizr{}",function(t){t.hidden=!0,d="none"==(e.getComputedStyle?getComputedStyle(t,null):t.currentStyle).display}),h=1==n.childNodes.length||function(){try{t.createElement("a")}catch(e){return!0}var n=t.createDocumentFragment();return n.cloneNode===void 0||n.createDocumentFragment===void 0||n.createElement===void 0}()})();var m={elements:p.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:p.shivCSS!==!1,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:o};e.html5=m,o(t);var v=/^$|\b(?:all|print)\b/,b="html5shiv",y=!h&&function(){var n=t.documentElement;return t.namespaces!==void 0&&t.parentWindow!==void 0&&n.applyElement!==void 0&&n.removeNode!==void 0&&e.attachEvent!==void 0}();m.type+=" print",m.shivPrint=u,u(t)})(this,document); -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/select2.dist.css/select2-bootstrap.css: -------------------------------------------------------------------------------- 1 | .form-control .select2-choice { 2 | border: 0; 3 | border-radius: 2px; 4 | } 5 | 6 | .form-control .select2-choice .select2-arrow { 7 | border-radius: 0 2px 2px 0; 8 | } 9 | 10 | .form-control.select2-container { 11 | height: auto !important; 12 | padding: 0; 13 | } 14 | 15 | .form-control.select2-container.select2-dropdown-open { 16 | border-color: #5897FB; 17 | border-radius: 3px 3px 0 0; 18 | } 19 | 20 | .form-control .select2-container.select2-dropdown-open .select2-choices { 21 | border-radius: 3px 3px 0 0; 22 | } 23 | 24 | .form-control.select2-container .select2-choices { 25 | border: 0 !important; 26 | border-radius: 3px; 27 | } 28 | 29 | .control-group.warning .select2-container .select2-choice, 30 | .control-group.warning .select2-container .select2-choices, 31 | .control-group.warning .select2-container-active .select2-choice, 32 | .control-group.warning .select2-container-active .select2-choices, 33 | .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice, 34 | .control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices, 35 | .control-group.warning .select2-container-multi.select2-container-active .select2-choices { 36 | border: 1px solid #C09853 !important; 37 | } 38 | 39 | .control-group.warning .select2-container .select2-choice div { 40 | border-left: 1px solid #C09853 !important; 41 | background: #FCF8E3 !important; 42 | } 43 | 44 | .control-group.error .select2-container .select2-choice, 45 | .control-group.error .select2-container .select2-choices, 46 | .control-group.error .select2-container-active .select2-choice, 47 | .control-group.error .select2-container-active .select2-choices, 48 | .control-group.error .select2-dropdown-open.select2-drop-above .select2-choice, 49 | .control-group.error .select2-dropdown-open.select2-drop-above .select2-choices, 50 | .control-group.error .select2-container-multi.select2-container-active .select2-choices { 51 | border: 1px solid #B94A48 !important; 52 | } 53 | 54 | .control-group.error .select2-container .select2-choice div { 55 | border-left: 1px solid #B94A48 !important; 56 | background: #F2DEDE !important; 57 | } 58 | 59 | .control-group.info .select2-container .select2-choice, 60 | .control-group.info .select2-container .select2-choices, 61 | .control-group.info .select2-container-active .select2-choice, 62 | .control-group.info .select2-container-active .select2-choices, 63 | .control-group.info .select2-dropdown-open.select2-drop-above .select2-choice, 64 | .control-group.info .select2-dropdown-open.select2-drop-above .select2-choices, 65 | .control-group.info .select2-container-multi.select2-container-active .select2-choices { 66 | border: 1px solid #3A87AD !important; 67 | } 68 | 69 | .control-group.info .select2-container .select2-choice div { 70 | border-left: 1px solid #3A87AD !important; 71 | background: #D9EDF7 !important; 72 | } 73 | 74 | .control-group.success .select2-container .select2-choice, 75 | .control-group.success .select2-container .select2-choices, 76 | .control-group.success .select2-container-active .select2-choice, 77 | .control-group.success .select2-container-active .select2-choices, 78 | .control-group.success .select2-dropdown-open.select2-drop-above .select2-choice, 79 | .control-group.success .select2-dropdown-open.select2-drop-above .select2-choices, 80 | .control-group.success .select2-container-multi.select2-container-active .select2-choices { 81 | border: 1px solid #468847 !important; 82 | } 83 | 84 | .control-group.success .select2-container .select2-choice div { 85 | border-left: 1px solid #468847 !important; 86 | background: #DFF0D8 !important; 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Bo/RestResponseBo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Bo; 2 | 3 | /** 4 | * rest返回对象 5 | *^ 6 | * @param 7 | */ 8 | public class RestResponseBo { 9 | 10 | /** 11 | * 服务器响应数据 12 | */ 13 | private T payload; 14 | 15 | /** 16 | * 请求是否成功 17 | */ 18 | private boolean success; 19 | 20 | /** 21 | * 错误信息 22 | */ 23 | private String msg; 24 | 25 | /** 26 | * 状态码 27 | */ 28 | private int code = -1; 29 | 30 | /** 31 | * 服务器响应时间 32 | */ 33 | private long timestamp; 34 | 35 | public RestResponseBo() { 36 | this.timestamp = System.currentTimeMillis() / 1000; 37 | } 38 | 39 | public RestResponseBo(boolean success) { 40 | this.timestamp = System.currentTimeMillis() / 1000; 41 | this.success = success; 42 | } 43 | 44 | public RestResponseBo(boolean success, T payload) { 45 | this.timestamp = System.currentTimeMillis() / 1000; 46 | this.success = success; 47 | this.payload = payload; 48 | } 49 | 50 | public RestResponseBo(boolean success, T payload, int code) { 51 | this.timestamp = System.currentTimeMillis() / 1000; 52 | this.success = success; 53 | this.payload = payload; 54 | this.code = code; 55 | } 56 | 57 | public RestResponseBo(boolean success, String msg) { 58 | this.timestamp = System.currentTimeMillis() / 1000; 59 | this.success = success; 60 | this.msg = msg; 61 | } 62 | 63 | public RestResponseBo(boolean success, String msg, int code) { 64 | this.timestamp = System.currentTimeMillis() / 1000; 65 | this.success = success; 66 | this.msg = msg; 67 | this.code = code; 68 | } 69 | 70 | public T getPayload() { 71 | return payload; 72 | } 73 | 74 | public void setPayload(T payload) { 75 | this.payload = payload; 76 | } 77 | 78 | public boolean isSuccess() { 79 | return success; 80 | } 81 | 82 | public void setSuccess(boolean success) { 83 | this.success = success; 84 | } 85 | 86 | public String getMsg() { 87 | return msg; 88 | } 89 | 90 | public void setMsg(String msg) { 91 | this.msg = msg; 92 | } 93 | 94 | public int getCode() { 95 | return code; 96 | } 97 | 98 | public void setCode(int code) { 99 | this.code = code; 100 | } 101 | 102 | public long getTimestamp() { 103 | return timestamp; 104 | } 105 | 106 | public void setTimestamp(long timestamp) { 107 | this.timestamp = timestamp; 108 | } 109 | 110 | public static RestResponseBo ok() { 111 | return new RestResponseBo(true); 112 | } 113 | 114 | public static RestResponseBo ok(T payload) { 115 | return new RestResponseBo(true, payload); 116 | } 117 | 118 | public static RestResponseBo ok(int code) { 119 | return new RestResponseBo(true, null, code); 120 | } 121 | 122 | public static RestResponseBo ok(T payload, int code) { 123 | return new RestResponseBo(true, payload, code); 124 | } 125 | 126 | public static RestResponseBo fail() { 127 | return new RestResponseBo(false); 128 | } 129 | 130 | public static RestResponseBo fail(String msg) { 131 | return new RestResponseBo(false, msg); 132 | } 133 | 134 | public static RestResponseBo fail(int code) { 135 | return new RestResponseBo(false, null, code); 136 | } 137 | 138 | public static RestResponseBo fail(int code, String msg) { 139 | return new RestResponseBo(false, msg, code); 140 | } 141 | 142 | } -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/install.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 13 on 2017/2/23. 3 | */ 4 | !function ($) { 5 | "use strict"; 6 | var tale = new $.tale(); 7 | var FormWizard = function () { 8 | }; 9 | //creates form with validation 10 | FormWizard.prototype.init = function () { 11 | var $form_container = $("#wizard-validation-form"); 12 | $form_container.validate({ 13 | errorPlacement: function errorPlacement(error, element) { 14 | element.after(error); 15 | } 16 | }); 17 | $("#steps").steps({ 18 | headerTag: "h3", 19 | bodyTag: "section", 20 | transitionEffect: "fade", 21 | labels: { 22 | previous: "上一步", 23 | next: "下一步", 24 | finish: "登录后台", 25 | loading: '加载中...', 26 | current: '当前位置' 27 | }, 28 | onStepChanging: function (event, currentIndex, newIndex) { 29 | tale.showLoading(); 30 | $form_container.validate().settings.ignore = ":disabled,:hidden"; 31 | var isValid=true; 32 | if(newIndex!=0){ 33 | isValid = $form_container.valid(); 34 | if(!isValid){ 35 | tale.hideLoading(); 36 | } 37 | } 38 | if (isValid && currentIndex == 1&&newIndex==2) { 39 | isValid = false; 40 | var params = $form_container.serialize(); 41 | tale.post({ 42 | url: '/install/testCon', 43 | data: params, 44 | success: function (result) { 45 | if (result && result.success) { 46 | tale.showLoading(); 47 | tale.post({ 48 | url: '/install', 49 | data: params, 50 | success: function (result) { 51 | if (result && result.success) { 52 | isValid = true; 53 | } else { 54 | if (result.msg) { 55 | tale.alertError(result.msg || '安装失败'); 56 | } 57 | } 58 | } 59 | }); 60 | } else { 61 | tale.alertError(result.msg || '测试连接失败'); 62 | } 63 | } 64 | }); 65 | return isValid; 66 | } else { 67 | tale.hideLoading(); 68 | return isValid; 69 | } 70 | }, 71 | onStepChanged: function (event, currentIndex) { 72 | tale.hideLoading(); 73 | }, 74 | onFinishing: function (event, currentIndex) { 75 | $form_container.validate().settings.ignore = ":disabled"; 76 | var isValid = $form_container.valid(); 77 | window.location.href = "/admin/login"; 78 | return isValid; 79 | }, 80 | onFinished: function (event, currentIndex) { 81 | window.location.href = "/admin/login"; 82 | } 83 | }); 84 | return $form_container; 85 | }, 86 | //init 87 | $.FormWizard = new FormWizard, $.FormWizard.Constructor = FormWizard 88 | }(window.jQuery), $.FormWizard.init(); -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/CommentVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class CommentVo implements Serializable { 9 | /** 10 | * comment表主键 11 | */ 12 | private Integer coid; 13 | 14 | /** 15 | * post表主键,关联字段 16 | */ 17 | private Integer cid; 18 | 19 | /** 20 | * 评论生成时的GMT unix时间戳 21 | */ 22 | private Integer created; 23 | 24 | /** 25 | * 评论作者 26 | */ 27 | private String author; 28 | 29 | /** 30 | * 评论所属用户id 31 | */ 32 | private Integer authorId; 33 | 34 | /** 35 | * 评论所属内容作者id 36 | */ 37 | private Integer ownerId; 38 | 39 | /** 40 | * 评论者邮件 41 | */ 42 | private String mail; 43 | 44 | /** 45 | * 评论者网址 46 | */ 47 | private String url; 48 | 49 | /** 50 | * 评论者ip地址 51 | */ 52 | private String ip; 53 | 54 | /** 55 | * 评论者客户端 56 | */ 57 | private String agent; 58 | 59 | /** 60 | * 评论类型 61 | */ 62 | private String type; 63 | 64 | /** 65 | * 评论状态 66 | */ 67 | private String status; 68 | 69 | /** 70 | * 父级评论 71 | */ 72 | private Integer parent; 73 | 74 | /** 75 | * 评论内容 76 | */ 77 | private String content; 78 | 79 | private static final long serialVersionUID = 1L; 80 | 81 | public Integer getCoid() { 82 | return coid; 83 | } 84 | 85 | public void setCoid(Integer coid) { 86 | this.coid = coid; 87 | } 88 | 89 | public Integer getCid() { 90 | return cid; 91 | } 92 | 93 | public void setCid(Integer cid) { 94 | this.cid = cid; 95 | } 96 | 97 | public Integer getCreated() { 98 | return created; 99 | } 100 | 101 | public void setCreated(Integer created) { 102 | this.created = created; 103 | } 104 | 105 | public String getAuthor() { 106 | return author; 107 | } 108 | 109 | public void setAuthor(String author) { 110 | this.author = author; 111 | } 112 | 113 | public Integer getAuthorId() { 114 | return authorId; 115 | } 116 | 117 | public void setAuthorId(Integer authorId) { 118 | this.authorId = authorId; 119 | } 120 | 121 | public Integer getOwnerId() { 122 | return ownerId; 123 | } 124 | 125 | public void setOwnerId(Integer ownerId) { 126 | this.ownerId = ownerId; 127 | } 128 | 129 | public String getMail() { 130 | return mail; 131 | } 132 | 133 | public void setMail(String mail) { 134 | this.mail = mail; 135 | } 136 | 137 | public String getUrl() { 138 | return url; 139 | } 140 | 141 | public void setUrl(String url) { 142 | this.url = url; 143 | } 144 | 145 | public String getIp() { 146 | return ip; 147 | } 148 | 149 | public void setIp(String ip) { 150 | this.ip = ip; 151 | } 152 | 153 | public String getAgent() { 154 | return agent; 155 | } 156 | 157 | public void setAgent(String agent) { 158 | this.agent = agent; 159 | } 160 | 161 | public String getType() { 162 | return type; 163 | } 164 | 165 | public void setType(String type) { 166 | this.type = type; 167 | } 168 | 169 | public String getStatus() { 170 | return status; 171 | } 172 | 173 | public void setStatus(String status) { 174 | this.status = status; 175 | } 176 | 177 | public Integer getParent() { 178 | return parent; 179 | } 180 | 181 | public void setParent(Integer parent) { 182 | this.parent = parent; 183 | } 184 | 185 | public String getContent() { 186 | return content; 187 | } 188 | 189 | public void setContent(String content) { 190 | this.content = content; 191 | } 192 | } -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl 2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT 3 | * */ 4 | 5 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b 2 | 3 |
4 | 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |

文章管理

13 |
14 |
15 |
16 | 添加新页面 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 38 | 48 | 49 | 50 | 51 |
页面名称页面路径发布时间发布状态操作
35 | 36 | 37 | 39 | 编辑 41 | 删除 44 | 预览 47 |
52 | 53 | 54 |
55 | 56 | 57 | 58 | 59 |
60 | 83 | 84 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/controller/admin/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller.admin; 2 | 3 | import com.my.blog.website.constant.WebConst; 4 | import com.my.blog.website.controller.BaseController; 5 | import com.my.blog.website.dto.LogActions; 6 | import com.my.blog.website.exception.TipException; 7 | import com.my.blog.website.modal.Bo.RestResponseBo; 8 | import com.my.blog.website.modal.Vo.UserVo; 9 | import com.my.blog.website.service.ILogService; 10 | import com.my.blog.website.service.IUserService; 11 | import com.my.blog.website.utils.Commons; 12 | import com.my.blog.website.utils.TaleUtils; 13 | import org.apache.catalina.servlet4preview.http.HttpServletRequest; 14 | import org.apache.commons.lang3.StringUtils; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | import org.springframework.stereotype.Controller; 18 | import org.springframework.transaction.annotation.Transactional; 19 | import org.springframework.web.bind.annotation.*; 20 | 21 | import javax.annotation.Resource; 22 | import javax.servlet.http.Cookie; 23 | import javax.servlet.http.HttpServletResponse; 24 | import javax.servlet.http.HttpSession; 25 | import java.io.IOException; 26 | 27 | /** 28 | * 用户后台登录/登出 29 | * Created by BlueT on 2017/3/11. 30 | */ 31 | @Controller 32 | @RequestMapping("/admin") 33 | @Transactional(rollbackFor = TipException.class) 34 | public class AuthController extends BaseController { 35 | 36 | private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class); 37 | 38 | @Resource 39 | private IUserService usersService; 40 | 41 | @Resource 42 | private ILogService logService; 43 | 44 | @GetMapping(value = "/login") 45 | public String login() { 46 | return "admin/login"; 47 | } 48 | 49 | /** 50 | * 管理后台登录 51 | * @param username 52 | * @param password 53 | * @param remeber_me 54 | * @param request 55 | * @param response 56 | * @return 57 | */ 58 | @PostMapping(value = "login") 59 | @ResponseBody 60 | public RestResponseBo doLogin(@RequestParam String username, 61 | @RequestParam String password, 62 | @RequestParam(required = false) String remeber_me, 63 | HttpServletRequest request, 64 | HttpServletResponse response) { 65 | 66 | Integer error_count = cache.get("login_error_count"); 67 | try { 68 | UserVo user = usersService.login(username, password); 69 | request.getSession().setAttribute(WebConst.LOGIN_SESSION_KEY, user); 70 | if (StringUtils.isNotBlank(remeber_me)) { 71 | TaleUtils.setCookie(response, user.getUid()); 72 | } 73 | logService.insertLog(LogActions.LOGIN.getAction(), null, request.getRemoteAddr(), user.getUid()); 74 | } catch (Exception e) { 75 | error_count = null == error_count ? 1 : error_count + 1; 76 | if (error_count > 3) { 77 | return RestResponseBo.fail("您输入密码已经错误超过3次,请10分钟后尝试"); 78 | } 79 | cache.set("login_error_count", error_count, 10 * 60); 80 | String msg = "登录失败"; 81 | if (e instanceof TipException) { 82 | msg = e.getMessage(); 83 | } else { 84 | LOGGER.error(msg, e); 85 | } 86 | return RestResponseBo.fail(msg); 87 | } 88 | return RestResponseBo.ok(); 89 | } 90 | 91 | /** 92 | * 注销 93 | * @param session 94 | * @param response 95 | */ 96 | @RequestMapping("/logout") 97 | public void logout(HttpSession session, HttpServletResponse response, HttpServletRequest request) { 98 | session.removeAttribute(WebConst.LOGIN_SESSION_KEY); 99 | Cookie cookie = new Cookie(WebConst.USER_IN_COOKIE, ""); 100 | cookie.setMaxAge(0); 101 | response.addCookie(cookie); 102 | try { 103 | //response.sendRedirect(Commons.site_url()); 104 | response.sendRedirect(Commons.site_login()); 105 | } catch (IOException e) { 106 | e.printStackTrace(); 107 | LOGGER.error("注销失败", e); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/utils/MapCache.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.utils; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * map缓存实现 8 | *

9 | * Created by 13 on 2017/2/7. 10 | */ 11 | public class MapCache { 12 | 13 | /** 14 | * 默认存储1024个缓存 15 | */ 16 | private static final int DEFAULT_CACHES = 1024; 17 | 18 | private static final MapCache INS = new MapCache(); 19 | 20 | public static MapCache single() { 21 | return INS; 22 | } 23 | 24 | /** 25 | * 缓存容器 26 | */ 27 | private Map cachePool; 28 | 29 | public MapCache() { 30 | this(DEFAULT_CACHES); 31 | } 32 | 33 | public MapCache(int cacheCount) { 34 | cachePool = new ConcurrentHashMap<>(cacheCount); 35 | } 36 | 37 | /** 38 | * 读取一个缓存 39 | * 40 | * @param key 缓存key 41 | * @param 42 | * @return 43 | */ 44 | public T get(String key) { 45 | CacheObject cacheObject = cachePool.get(key); 46 | if (null != cacheObject) { 47 | long cur = System.currentTimeMillis() / 1000; 48 | if (cacheObject.getExpired() <= 0 || cacheObject.getExpired() > cur) { 49 | Object result = cacheObject.getValue(); 50 | return (T) result; 51 | } 52 | } 53 | return null; 54 | } 55 | 56 | /** 57 | * 读取一个hash类型缓存 58 | * 59 | * @param key 缓存key 60 | * @param field 缓存field 61 | * @param 62 | * @return 63 | */ 64 | public T hget(String key, String field) { 65 | key = key + ":" + field; 66 | return this.get(key); 67 | } 68 | 69 | /** 70 | * 设置一个缓存 71 | * 72 | * @param key 缓存key 73 | * @param value 缓存value 74 | */ 75 | public void set(String key, Object value) { 76 | this.set(key, value, -1); 77 | } 78 | 79 | /** 80 | * 设置一个缓存并带过期时间 81 | * 82 | * @param key 缓存key 83 | * @param value 缓存value 84 | * @param expired 过期时间,单位为秒 85 | */ 86 | public void set(String key, Object value, long expired) { 87 | expired = expired > 0 ? System.currentTimeMillis() / 1000 + expired : expired; 88 | CacheObject cacheObject = new CacheObject(key, value, expired); 89 | cachePool.put(key, cacheObject); 90 | } 91 | 92 | /** 93 | * 设置一个hash缓存 94 | * 95 | * @param key 缓存key 96 | * @param field 缓存field 97 | * @param value 缓存value 98 | */ 99 | public void hset(String key, String field, Object value) { 100 | this.hset(key, field, value, -1); 101 | } 102 | 103 | /** 104 | * 设置一个hash缓存并带过期时间 105 | * 106 | * @param key 缓存key 107 | * @param field 缓存field 108 | * @param value 缓存value 109 | * @param expired 过期时间,单位为秒 110 | */ 111 | public void hset(String key, String field, Object value, long expired) { 112 | key = key + ":" + field; 113 | expired = expired > 0 ? System.currentTimeMillis() / 1000 + expired : expired; 114 | CacheObject cacheObject = new CacheObject(key, value, expired); 115 | cachePool.put(key, cacheObject); 116 | } 117 | 118 | /** 119 | * 根据key删除缓存 120 | * 121 | * @param key 缓存key 122 | */ 123 | public void del(String key) { 124 | cachePool.remove(key); 125 | } 126 | 127 | /** 128 | * 根据key和field删除缓存 129 | * 130 | * @param key 缓存key 131 | * @param field 缓存field 132 | */ 133 | public void hdel(String key, String field) { 134 | key = key + ":" + field; 135 | this.del(key); 136 | } 137 | 138 | /** 139 | * 清空缓存 140 | */ 141 | public void clean() { 142 | cachePool.clear(); 143 | } 144 | 145 | static class CacheObject { 146 | private String key; 147 | private Object value; 148 | private long expired; 149 | 150 | public CacheObject(String key, Object value, long expired) { 151 | this.key = key; 152 | this.value = value; 153 | this.expired = expired; 154 | } 155 | 156 | public String getKey() { 157 | return key; 158 | } 159 | 160 | public Object getValue() { 161 | return value; 162 | } 163 | 164 | public long getExpired() { 165 | return expired; 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/modal/Vo/ContentVo.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.modal.Vo; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author 7 | */ 8 | public class ContentVo implements Serializable { 9 | /** 10 | * post表主键 11 | */ 12 | private Integer cid; 13 | 14 | /** 15 | * 内容标题 16 | */ 17 | private String title; 18 | 19 | /** 20 | * 内容缩略名 21 | */ 22 | private String slug; 23 | 24 | /** 25 | * 内容生成时的GMT unix时间戳 26 | */ 27 | private Integer created; 28 | 29 | /** 30 | * 内容更改时的GMT unix时间戳 31 | */ 32 | private Integer modified; 33 | 34 | /** 35 | * 内容所属用户id 36 | */ 37 | private Integer authorId; 38 | 39 | /** 40 | * 内容类别 41 | */ 42 | private String type; 43 | 44 | /** 45 | * 内容状态 46 | */ 47 | private String status; 48 | 49 | /** 50 | * 标签列表 51 | */ 52 | private String tags; 53 | 54 | /** 55 | * 分类列表 56 | */ 57 | private String categories; 58 | 59 | /** 60 | * 点击次数 61 | */ 62 | private Integer hits; 63 | 64 | /** 65 | * 内容所属评论数 66 | */ 67 | private Integer commentsNum; 68 | 69 | /** 70 | * 是否允许评论 71 | */ 72 | private Boolean allowComment; 73 | 74 | /** 75 | * 是否允许ping 76 | */ 77 | private Boolean allowPing; 78 | 79 | /** 80 | * 允许出现在聚合中 81 | */ 82 | private Boolean allowFeed; 83 | 84 | /** 85 | * 内容文字 86 | */ 87 | private String content; 88 | 89 | private static final long serialVersionUID = 1L; 90 | 91 | public Integer getCid() { 92 | return cid; 93 | } 94 | 95 | public void setCid(Integer cid) { 96 | this.cid = cid; 97 | } 98 | 99 | public String getTitle() { 100 | return title; 101 | } 102 | 103 | public void setTitle(String title) { 104 | this.title = title; 105 | } 106 | 107 | public String getSlug() { 108 | return slug; 109 | } 110 | 111 | public void setSlug(String slug) { 112 | this.slug = slug; 113 | } 114 | 115 | public Integer getCreated() { 116 | return created; 117 | } 118 | 119 | public void setCreated(Integer created) { 120 | this.created = created; 121 | } 122 | 123 | public Integer getModified() { 124 | return modified; 125 | } 126 | 127 | public void setModified(Integer modified) { 128 | this.modified = modified; 129 | } 130 | 131 | public Integer getAuthorId() { 132 | return authorId; 133 | } 134 | 135 | public void setAuthorId(Integer authorId) { 136 | this.authorId = authorId; 137 | } 138 | 139 | public String getType() { 140 | return type; 141 | } 142 | 143 | public void setType(String type) { 144 | this.type = type; 145 | } 146 | 147 | public String getStatus() { 148 | return status; 149 | } 150 | 151 | public void setStatus(String status) { 152 | this.status = status; 153 | } 154 | 155 | public String getTags() { 156 | return tags; 157 | } 158 | 159 | public void setTags(String tags) { 160 | this.tags = tags; 161 | } 162 | 163 | public String getCategories() { 164 | return categories; 165 | } 166 | 167 | public void setCategories(String categories) { 168 | this.categories = categories; 169 | } 170 | 171 | public Integer getHits() { 172 | return hits; 173 | } 174 | 175 | public void setHits(Integer hits) { 176 | this.hits = hits; 177 | } 178 | 179 | public Integer getCommentsNum() { 180 | return commentsNum; 181 | } 182 | 183 | public void setCommentsNum(Integer commentsNum) { 184 | this.commentsNum = commentsNum; 185 | } 186 | 187 | public Boolean getAllowComment() { 188 | return allowComment; 189 | } 190 | 191 | public void setAllowComment(Boolean allowComment) { 192 | this.allowComment = allowComment; 193 | } 194 | 195 | public Boolean getAllowPing() { 196 | return allowPing; 197 | } 198 | 199 | public void setAllowPing(Boolean allowPing) { 200 | this.allowPing = allowPing; 201 | } 202 | 203 | public Boolean getAllowFeed() { 204 | return allowFeed; 205 | } 206 | 207 | public void setAllowFeed(Boolean allowFeed) { 208 | this.allowFeed = allowFeed; 209 | } 210 | 211 | public String getContent() { 212 | return content; 213 | } 214 | 215 | public void setContent(String content) { 216 | this.content = content; 217 | } 218 | } -------------------------------------------------------------------------------- /src/main/resources/templates/admin/article_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |

文章管理

13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 43 | 54 | 55 | 56 | 57 | 58 |
文章标题发布时间浏览量所属分类发布状态操作
30 | 31 | 36 | 37 | 已发布 38 | 39 | 40 | 草稿 41 | 42 | 44 | 编辑 47 | 删除 50 | 预览 53 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | 91 | 92 | -------------------------------------------------------------------------------- /src/main/resources/static/admin/js/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tale全局函数对象 var tale = new $.tale(); 3 | */ 4 | $.extend({ 5 | tale: function () { 6 | } 7 | }); 8 | 9 | /** 10 | * tale alert删除 // todo: 减少耦合度,链式操作替代 2017-02-27 11 | * @param options 12 | */ 13 | // $.tale.prototype.alert_del = function (options) { 14 | // swal({ 15 | // title: options.title || '警告信息', 16 | // text: options.text || "确定删除吗?", 17 | // type: 'warning', 18 | // showCancelButton: true, 19 | // confirmButtonColor: '#3085d6', 20 | // cancelButtonColor: '#d33', 21 | // confirmButtonText: '确定', 22 | // cancelButtonText: '取消' 23 | // }).then(function () { 24 | // $.post(options.url, options.parame, function (result) { 25 | // if (result && result.success) { 26 | // swal('提示信息', '删除成功', 'success'); 27 | // setTimeout(function () { 28 | // window.location.reload(); 29 | // }, 2000); 30 | // } else { 31 | // swal("提示消息", result.msg, 'error'); 32 | // } 33 | // }); 34 | // }).catch(swal.noop); 35 | // }; 36 | 37 | /** 38 | * 成功弹框 39 | * @param options 40 | */ 41 | $.tale.prototype.alertOk = function (options) { 42 | options = options.length ? {text:options} : ( options || {} ); 43 | options.title = options.title || '操作成功'; 44 | options.text = options.text; 45 | options.showCancelButton = false; 46 | options.showCloseButton = false; 47 | options.type = 'success'; 48 | this.alertBox(options); 49 | }; 50 | 51 | /** 52 | * 弹出成功,并在500毫秒后刷新页面 53 | * @param text 54 | */ 55 | $.tale.prototype.alertOkAndReload = function (text) { 56 | this.alertOk({text:text, then:function () { 57 | setTimeout(function () { 58 | window.location.reload(); 59 | }, 500); 60 | }}); 61 | }; 62 | 63 | /** 64 | * 警告弹框 65 | * @param options 66 | */ 67 | $.tale.prototype.alertWarn = function (options) { 68 | options = options.length ? {text:options} : ( options || {} ); 69 | options.title = options.title || '警告信息'; 70 | options.text = options.text; 71 | options.timer = 3000; 72 | options.type = 'warning'; 73 | this.alertBox(options); 74 | }; 75 | 76 | /** 77 | * 询问确认弹框,这里会传入then函数进来 78 | * @param options 79 | */ 80 | $.tale.prototype.alertConfirm = function (options) { 81 | options = options || {}; 82 | options.title = options.title || '确定要删除吗?'; 83 | options.text = options.text; 84 | options.showCancelButton = true; 85 | options.type = 'question'; 86 | this.alertBox(options); 87 | }; 88 | 89 | /** 90 | * 错误提示 91 | * @param options 92 | */ 93 | $.tale.prototype.alertError = function (options) { 94 | options = options.length ? {text:options} : ( options || {} ); 95 | options.title = options.title || '错误信息'; 96 | options.text = options.text; 97 | options.type = 'error'; 98 | this.alertBox(options); 99 | }; 100 | 101 | /** 102 | * 公共弹框 103 | * @param options 104 | */ 105 | $.tale.prototype.alertBox = function (options) { 106 | swal({ 107 | title: options.title, 108 | text: options.text, 109 | type: options.type, 110 | timer: options.timer || 9999, 111 | showCloseButton: options.showCloseButton, 112 | showCancelButton: options.showCancelButton, 113 | showLoaderOnConfirm: options.showLoaderOnConfirm || false, 114 | confirmButtonColor: options.confirmButtonColor || '#3085d6', 115 | cancelButtonColor: options.cancelButtonColor || '#d33', 116 | confirmButtonText: options.confirmButtonText || '确定', 117 | cancelButtonText: options.cancelButtonText || '取消' 118 | }).then(function (e) { 119 | options.then && options.then(e); 120 | }).catch(swal.noop); 121 | }; 122 | 123 | /** 124 | * 全局post函数 125 | * 126 | * @param options 参数 127 | */ 128 | $.tale.prototype.post = function (options) { 129 | var self = this; 130 | $.ajax({ 131 | type: 'POST', 132 | url: options.url, 133 | data: options.data || {}, 134 | async: options.async || false, 135 | dataType: 'json', 136 | success: function (result) { 137 | self.hideLoading(); 138 | options.success && options.success(result); 139 | }, 140 | error: function () { 141 | // 142 | } 143 | }); 144 | }; 145 | 146 | /** 147 | * 显示动画 148 | */ 149 | $.tale.prototype.showLoading = function () { 150 | if ($('#tale-loading').length == 0) { 151 | $('body').append('
'); 152 | } 153 | $('#tale-loading').show(); 154 | }; 155 | 156 | /** 157 | * 隐藏动画 158 | */ 159 | $.tale.prototype.hideLoading = function () { 160 | $('#tale-loading') && $('#tale-loading').hide(); 161 | }; -------------------------------------------------------------------------------- /src/main/resources/static/admin/plugins/jquery-multi-select/jquery.quicksearch.js: -------------------------------------------------------------------------------- 1 | (function($, window, document, undefined) { 2 | $.fn.quicksearch = function (target, opt) { 3 | 4 | var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({ 5 | delay: 100, 6 | selector: null, 7 | stripeRows: null, 8 | loader: null, 9 | noResults: '', 10 | matchedResultsCount: 0, 11 | bind: 'keyup', 12 | onBefore: function () { 13 | return; 14 | }, 15 | onAfter: function () { 16 | return; 17 | }, 18 | show: function () { 19 | this.style.display = ""; 20 | }, 21 | hide: function () { 22 | this.style.display = "none"; 23 | }, 24 | prepareQuery: function (val) { 25 | return val.toLowerCase().split(' '); 26 | }, 27 | testQuery: function (query, txt, _row) { 28 | for (var i = 0; i < query.length; i += 1) { 29 | if (txt.indexOf(query[i]) === -1) { 30 | return false; 31 | } 32 | } 33 | return true; 34 | } 35 | }, opt); 36 | 37 | this.go = function () { 38 | 39 | var i = 0, 40 | numMatchedRows = 0, 41 | noresults = true, 42 | query = options.prepareQuery(val), 43 | val_empty = (val.replace(' ', '').length === 0); 44 | 45 | for (var i = 0, len = rowcache.length; i < len; i++) { 46 | if (val_empty || options.testQuery(query, cache[i], rowcache[i])) { 47 | options.show.apply(rowcache[i]); 48 | noresults = false; 49 | numMatchedRows++; 50 | } else { 51 | options.hide.apply(rowcache[i]); 52 | } 53 | } 54 | 55 | if (noresults) { 56 | this.results(false); 57 | } else { 58 | this.results(true); 59 | this.stripe(); 60 | } 61 | 62 | this.matchedResultsCount = numMatchedRows; 63 | this.loader(false); 64 | options.onAfter(); 65 | 66 | return this; 67 | }; 68 | 69 | /* 70 | * External API so that users can perform search programatically. 71 | * */ 72 | this.search = function (submittedVal) { 73 | val = submittedVal; 74 | e.trigger(); 75 | }; 76 | 77 | /* 78 | * External API to get the number of matched results as seen in 79 | * https://github.com/ruiz107/quicksearch/commit/f78dc440b42d95ce9caed1d087174dd4359982d6 80 | * */ 81 | this.currentMatchedResults = function() { 82 | return this.matchedResultsCount; 83 | }; 84 | 85 | this.stripe = function () { 86 | 87 | if (typeof options.stripeRows === "object" && options.stripeRows !== null) 88 | { 89 | var joined = options.stripeRows.join(' '); 90 | var stripeRows_length = options.stripeRows.length; 91 | 92 | jq_results.not(':hidden').each(function (i) { 93 | $(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]); 94 | }); 95 | } 96 | 97 | return this; 98 | }; 99 | 100 | this.strip_html = function (input) { 101 | var output = input.replace(new RegExp('<[^<]+\>', 'g'), ""); 102 | output = $.trim(output.toLowerCase()); 103 | return output; 104 | }; 105 | 106 | this.results = function (bool) { 107 | if (typeof options.noResults === "string" && options.noResults !== "") { 108 | if (bool) { 109 | $(options.noResults).hide(); 110 | } else { 111 | $(options.noResults).show(); 112 | } 113 | } 114 | return this; 115 | }; 116 | 117 | this.loader = function (bool) { 118 | if (typeof options.loader === "string" && options.loader !== "") { 119 | (bool) ? $(options.loader).show() : $(options.loader).hide(); 120 | } 121 | return this; 122 | }; 123 | 124 | this.cache = function () { 125 | 126 | jq_results = $(target); 127 | 128 | if (typeof options.noResults === "string" && options.noResults !== "") { 129 | jq_results = jq_results.not(options.noResults); 130 | } 131 | 132 | var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults); 133 | cache = t.map(function () { 134 | return e.strip_html(this.innerHTML); 135 | }); 136 | 137 | rowcache = jq_results.map(function () { 138 | return this; 139 | }); 140 | 141 | /* 142 | * Modified fix for sync-ing "val". 143 | * Original fix https://github.com/michaellwest/quicksearch/commit/4ace4008d079298a01f97f885ba8fa956a9703d1 144 | * */ 145 | val = val || this.val() || ""; 146 | 147 | return this.go(); 148 | }; 149 | 150 | this.trigger = function () { 151 | this.loader(true); 152 | options.onBefore(); 153 | 154 | window.clearTimeout(timeout); 155 | timeout = window.setTimeout(function () { 156 | e.go(); 157 | }, options.delay); 158 | 159 | return this; 160 | }; 161 | 162 | this.cache(); 163 | this.results(true); 164 | this.stripe(); 165 | this.loader(false); 166 | 167 | return this.each(function () { 168 | 169 | /* 170 | * Changed from .bind to .on. 171 | * */ 172 | $(this).on(options.bind, function () { 173 | 174 | val = $(this).val(); 175 | e.trigger(); 176 | }); 177 | }); 178 | 179 | }; 180 | 181 | }(jQuery, this, document)); 182 | -------------------------------------------------------------------------------- /src/main/java/com/my/blog/website/controller/admin/SettingController.java: -------------------------------------------------------------------------------- 1 | package com.my.blog.website.controller.admin; 2 | 3 | import com.my.blog.website.service.ILogService; 4 | import com.my.blog.website.service.ISiteService; 5 | import com.my.blog.website.constant.WebConst; 6 | import com.my.blog.website.controller.BaseController; 7 | import com.my.blog.website.dto.LogActions; 8 | import com.my.blog.website.exception.TipException; 9 | import com.my.blog.website.modal.Bo.BackResponseBo; 10 | import com.my.blog.website.modal.Bo.RestResponseBo; 11 | import com.my.blog.website.modal.Vo.OptionVo; 12 | import com.my.blog.website.service.IOptionService; 13 | import com.my.blog.website.utils.GsonUtils; 14 | import org.apache.commons.lang3.StringUtils; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | import org.springframework.stereotype.Controller; 18 | import org.springframework.transaction.annotation.Transactional; 19 | import org.springframework.web.bind.annotation.*; 20 | 21 | import javax.annotation.Resource; 22 | import javax.servlet.http.HttpServletRequest; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | /** 28 | * Created by wangq on 2017/3/20. 29 | */ 30 | @Controller 31 | @RequestMapping("/admin/setting") 32 | public class SettingController extends BaseController { 33 | private static final Logger LOGGER = LoggerFactory.getLogger(SettingController.class); 34 | 35 | @Resource 36 | private IOptionService optionService; 37 | 38 | @Resource 39 | private ILogService logService; 40 | 41 | @Resource 42 | private ISiteService siteService; 43 | 44 | /** 45 | * 系统设置 46 | */ 47 | @GetMapping(value = "") 48 | public String setting(HttpServletRequest request) { 49 | List voList = optionService.getOptions(); 50 | Map options = new HashMap<>(); 51 | voList.forEach((option) -> { 52 | options.put(option.getName(), option.getValue()); 53 | }); 54 | request.setAttribute("options", options); 55 | return "admin/setting"; 56 | } 57 | 58 | /** 59 | * 保存系统设置 60 | */ 61 | @PostMapping(value = "") 62 | @ResponseBody 63 | @Transactional(rollbackFor = TipException.class) 64 | public RestResponseBo saveSetting(@RequestParam(required = false) String site_theme, HttpServletRequest request) { 65 | try { 66 | Map parameterMap = request.getParameterMap(); 67 | Map querys = new HashMap<>(); 68 | parameterMap.forEach((key, value) -> { 69 | querys.put(key, join(value)); 70 | }); 71 | 72 | optionService.saveOptions(querys); 73 | 74 | WebConst.initConfig = querys; 75 | 76 | if (StringUtils.isNotBlank(site_theme)) { 77 | BaseController.THEME = "themes/" + site_theme; 78 | } 79 | logService.insertLog(LogActions.SYS_SETTING.getAction(), GsonUtils.toJsonString(querys), request.getRemoteAddr(), this.getUid(request)); 80 | return RestResponseBo.ok(); 81 | } catch (Exception e) { 82 | String msg = "保存设置失败"; 83 | if (e instanceof TipException) { 84 | msg = e.getMessage(); 85 | } else { 86 | LOGGER.error(msg, e); 87 | } 88 | return RestResponseBo.fail(msg); 89 | } 90 | } 91 | 92 | 93 | /** 94 | * 系统备份 95 | * 96 | * @return 97 | */ 98 | @PostMapping(value = "backup") 99 | @ResponseBody 100 | @Transactional(rollbackFor = TipException.class) 101 | public RestResponseBo backup(@RequestParam String bk_type, @RequestParam String bk_path, 102 | HttpServletRequest request) { 103 | if (StringUtils.isBlank(bk_type)) { 104 | return RestResponseBo.fail("请确认信息输入完整"); 105 | } 106 | try { 107 | BackResponseBo backResponse = siteService.backup(bk_type, bk_path, "yyyyMMddHHmm"); 108 | logService.insertLog(LogActions.SYS_BACKUP.getAction(), null, request.getRemoteAddr(), this.getUid(request)); 109 | return RestResponseBo.ok(backResponse); 110 | } catch (Exception e) { 111 | String msg = "备份失败"; 112 | if (e instanceof TipException) { 113 | msg = e.getMessage(); 114 | } else { 115 | LOGGER.error(msg, e); 116 | } 117 | return RestResponseBo.fail(msg); 118 | } 119 | } 120 | 121 | 122 | /** 123 | * 数组转字符串 124 | * 125 | * @param arr 126 | * @return 127 | */ 128 | private String join(String[] arr) { 129 | StringBuilder ret = new StringBuilder(); 130 | String[] var3 = arr; 131 | int var4 = arr.length; 132 | 133 | for (int var5 = 0; var5 < var4; ++var5) { 134 | String item = var3[var5]; 135 | ret.append(',').append(item); 136 | } 137 | return ret.length() > 0 ? ret.substring(1) : ret.toString(); 138 | } 139 | 140 | } 141 | --------------------------------------------------------------------------------