├── src ├── main │ ├── resources │ │ ├── application-prod.yml │ │ ├── application.yml │ │ ├── mapper │ │ │ ├── LogMapper.xml │ │ │ ├── OptionMapper.xml │ │ │ ├── UserMapper.xml │ │ │ ├── RelationShipMapper.xml │ │ │ ├── AttAchMapper.xml │ │ │ ├── CommentMapper.xml │ │ │ ├── MetaMapper.xml │ │ │ └── ContentMapper.xml │ │ └── application-dev.yml │ └── java │ │ └── com │ │ └── wip │ │ ├── utils │ │ ├── ZwzNullUtils.java │ │ ├── GsonUtils.java │ │ ├── DateKit.java │ │ ├── AdminCommons.java │ │ ├── IPKit.java │ │ ├── APIResponse.java │ │ ├── Tools.java │ │ ├── UUID.java │ │ ├── MapCache.java │ │ ├── IpInfoUtil.java │ │ ├── Commons.java │ │ └── TaleUtils.java │ │ ├── dto │ │ ├── MetaDto.java │ │ ├── BaseDto.java │ │ ├── cond │ │ │ ├── MetaCond.java │ │ │ ├── CommentCond.java │ │ │ └── ContentCond.java │ │ ├── StatisticsDto.java │ │ └── AttAchDto.java │ │ ├── MyBlogApplication.java │ │ ├── dao │ │ ├── LogDao.java │ │ ├── OptionDao.java │ │ ├── UserDao.java │ │ ├── AttAchDao.java │ │ ├── RelationShipDao.java │ │ ├── CommentDao.java │ │ ├── ContentDao.java │ │ └── MetaDao.java │ │ ├── constant │ │ ├── LogActions.java │ │ ├── Types.java │ │ ├── WebConst.java │ │ └── ErrorConstant.java │ │ ├── model │ │ ├── RelationShipDomain.java │ │ ├── OptionsDomain.java │ │ ├── AttAchDomain.java │ │ ├── LogDomain.java │ │ ├── MetaDomain.java │ │ ├── UserDomain.java │ │ ├── CommentDomain.java │ │ └── ContentDomain.java │ │ ├── service │ │ ├── log │ │ │ ├── LogService.java │ │ │ └── impl │ │ │ │ └── LogServiceImpl.java │ │ ├── user │ │ │ ├── UserService.java │ │ │ └── impl │ │ │ │ └── UserServiceImpl.java │ │ ├── site │ │ │ ├── SiteService.java │ │ │ └── impl │ │ │ │ └── SiteServiceImpl.java │ │ ├── option │ │ │ ├── OptionService.java │ │ │ └── impl │ │ │ │ └── OptionServiceImpl.java │ │ ├── attach │ │ │ ├── AttAchService.java │ │ │ └── impl │ │ │ │ └── AttAchServiceImpl.java │ │ ├── comment │ │ │ ├── CommentService.java │ │ │ └── impl │ │ │ │ └── CommentServiceImpl.java │ │ ├── article │ │ │ ├── ContentService.java │ │ │ └── impl │ │ │ │ └── ContentServiceImpl.java │ │ └── meta │ │ │ ├── MetaService.java │ │ │ └── impl │ │ │ └── MetaServiceImpl.java │ │ └── controller │ │ ├── BaseController.java │ │ ├── admin │ │ ├── SettingController.java │ │ ├── CategoryController.java │ │ ├── LinksController.java │ │ ├── CommentController.java │ │ ├── AuthController.java │ │ ├── IndexController.java │ │ ├── AttachController.java │ │ └── ArticleController.java │ │ └── HomeController.java └── test │ └── java │ └── com │ └── wip │ └── MyBlogApplicationTests.java ├── picture ├── picture1.png ├── picture10.png ├── picture11.png ├── picture12.png ├── picture2.png ├── picture3.png ├── picture4.png ├── picture5.png ├── picture6.png ├── picture7.png ├── picture8.png └── picture9.png ├── .gitattributes ├── files ├── 20220801 │ ├── 4761b2db414341bfb1c94692dd8b2105.docx │ ├── 5a898f2a9d784faf8242b1e391522c8c.docx │ ├── 8d58ea3a2a6c424b89792354d422af4d.docx │ ├── ba8a55045e4d428db367b158c4efa58a.docx │ ├── c6e86bb06cd4420bb2b6f72b3c90517d.docx │ └── fe9e346993894a64aa947abcba2ae51e.docx └── 20220802 │ ├── 9ed8229f36cc4646b56055b0a3ff143f.png │ ├── db1123eb5778495aaf613733e9a1a252.docx │ ├── f1bf44540b9942f2b9316b7a7134ea33.docx │ └── fdb1b2a6c8a34a0983470f39baa81ea2.docx ├── .gitignore ├── README.md └── pom.xml /src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: dev -------------------------------------------------------------------------------- /picture/picture1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture1.png -------------------------------------------------------------------------------- /picture/picture10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture10.png -------------------------------------------------------------------------------- /picture/picture11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture11.png -------------------------------------------------------------------------------- /picture/picture12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture12.png -------------------------------------------------------------------------------- /picture/picture2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture2.png -------------------------------------------------------------------------------- /picture/picture3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture3.png -------------------------------------------------------------------------------- /picture/picture4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture4.png -------------------------------------------------------------------------------- /picture/picture5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture5.png -------------------------------------------------------------------------------- /picture/picture6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture6.png -------------------------------------------------------------------------------- /picture/picture7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture7.png -------------------------------------------------------------------------------- /picture/picture8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture8.png -------------------------------------------------------------------------------- /picture/picture9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/picture/picture9.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java 2 | *.css linguist-language=java 3 | *.html linguist-language=java 4 | -------------------------------------------------------------------------------- /files/20220802/9ed8229f36cc4646b56055b0a3ff143f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220802/9ed8229f36cc4646b56055b0a3ff143f.png -------------------------------------------------------------------------------- /files/20220801/4761b2db414341bfb1c94692dd8b2105.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220801/4761b2db414341bfb1c94692dd8b2105.docx -------------------------------------------------------------------------------- /files/20220801/5a898f2a9d784faf8242b1e391522c8c.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220801/5a898f2a9d784faf8242b1e391522c8c.docx -------------------------------------------------------------------------------- /files/20220801/8d58ea3a2a6c424b89792354d422af4d.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220801/8d58ea3a2a6c424b89792354d422af4d.docx -------------------------------------------------------------------------------- /files/20220801/ba8a55045e4d428db367b158c4efa58a.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220801/ba8a55045e4d428db367b158c4efa58a.docx -------------------------------------------------------------------------------- /files/20220801/c6e86bb06cd4420bb2b6f72b3c90517d.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220801/c6e86bb06cd4420bb2b6f72b3c90517d.docx -------------------------------------------------------------------------------- /files/20220801/fe9e346993894a64aa947abcba2ae51e.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220801/fe9e346993894a64aa947abcba2ae51e.docx -------------------------------------------------------------------------------- /files/20220802/db1123eb5778495aaf613733e9a1a252.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220802/db1123eb5778495aaf613733e9a1a252.docx -------------------------------------------------------------------------------- /files/20220802/f1bf44540b9942f2b9316b7a7134ea33.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220802/f1bf44540b9942f2b9316b7a7134ea33.docx -------------------------------------------------------------------------------- /files/20220802/fdb1b2a6c8a34a0983470f39baa81ea2.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ynwynw/Springboot-Blog-public/HEAD/files/20220802/fdb1b2a6c8a34a0983470f39baa81ea2.docx -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/ZwzNullUtils.java: -------------------------------------------------------------------------------- 1 | package com.wip.utils; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * 判断为空工具类 7 | * @author 郑为中 8 | */ 9 | public class ZwzNullUtils { 10 | public static boolean isNull(String str){ 11 | if(str == null || Objects.equals("",str) || Objects.equals("null",str) || Objects.equals("undefined",str)) { 12 | return true; 13 | } 14 | return false; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/GsonUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 11:46 5 | **/ 6 | package com.wip.utils; 7 | 8 | import com.google.gson.Gson; 9 | 10 | /** 11 | * json转换工具 12 | */ 13 | public class GsonUtils { 14 | private static final Gson gson = new Gson(); 15 | 16 | public static String toJsonString(Object object) { 17 | return object == null ? null : gson.toJson(object); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/wip/MyBlogApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.wip; 2 | 3 | import com.wip.utils.Commons; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | 9 | @RunWith(SpringRunner.class) 10 | @SpringBootTest 11 | public class MyBlogApplicationTests { 12 | 13 | @Test 14 | public void contextLoads() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/MetaDto.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 16:59 5 | **/ 6 | package com.wip.dto; 7 | 8 | import com.wip.model.MetaDomain; 9 | 10 | /** 11 | * 标签、分类列表 12 | */ 13 | public class MetaDto extends MetaDomain { 14 | 15 | private int count; 16 | 17 | public int getCount() { 18 | return count; 19 | } 20 | 21 | public void setCount(int count) { 22 | this.count = count; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/BaseDto.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/3 16:30 5 | **/ 6 | package com.wip.dto; 7 | 8 | /** 9 | * 公共属性的类 10 | */ 11 | public class BaseDto { 12 | 13 | /** 14 | * 用户名 15 | */ 16 | private String userName; 17 | 18 | public void setUserName(String userName) { 19 | this.userName = userName; 20 | } 21 | 22 | public String getUserName() { 23 | return userName; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java 2 | *.css linguist-language=java 3 | *.html linguist-language=java 4 | target/ 5 | !.mvn/wrapper/maven-wrapper.jar 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | .mvn 22 | mvnw 23 | mvnw.cmd 24 | 25 | ### NetBeans ### 26 | /nbproject/private/ 27 | /build/ 28 | /nbbuild/ 29 | /dist/ 30 | /nbdist/ 31 | /.nb-gradle/ 32 | -------------------------------------------------------------------------------- /src/main/java/com/wip/MyBlogApplication.java: -------------------------------------------------------------------------------- 1 | package com.wip; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cache.annotation.EnableCaching; 7 | 8 | @SpringBootApplication 9 | @MapperScan("com.wip.dao") 10 | //@EnableCaching 11 | public class MyBlogApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(MyBlogApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/LogDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 17:07 5 | **/ 6 | package com.wip.dao; 7 | 8 | 9 | import com.wip.model.LogDomain; 10 | import org.apache.ibatis.annotations.Mapper; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 日志dao层接口 16 | */ 17 | @Mapper 18 | public interface LogDao { 19 | 20 | /** 21 | * 添加日志 22 | * @param logDomain 23 | * @return 24 | */ 25 | int addLog(LogDomain logDomain); 26 | 27 | /** 28 | * 获取日志 29 | * @return 30 | */ 31 | List getLogs(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/wip/constant/LogActions.java: -------------------------------------------------------------------------------- 1 | package com.wip.constant; 2 | 3 | /** 4 | * 日志表的action字段 5 | */ 6 | public enum LogActions { 7 | 8 | LOGIN("登录后台"), 9 | UP_PWD("修改密码"), 10 | UP_INFO("修改个人信息"), 11 | DEL_ARTICLE("删除文章"), 12 | SYS_SETTING("保存系统设置"), 13 | DEL_ATTACH("删除附件"); 14 | 15 | private String action; 16 | 17 | public String getAction() { 18 | return action; 19 | } 20 | 21 | public void setAction(String action) { 22 | this.action = action; 23 | } 24 | 25 | LogActions(String action) { 26 | this.action = action; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/cond/MetaCond.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 16:59 5 | **/ 6 | package com.wip.dto.cond; 7 | 8 | /** 9 | * Meta查询条件 10 | */ 11 | public class MetaCond { 12 | 13 | /** 14 | * 名称 15 | */ 16 | private String name; 17 | 18 | /** 19 | * 类型 20 | */ 21 | private String type; 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setType(String type) { 32 | this.type = type; 33 | } 34 | 35 | public String getType() { 36 | return type; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/RelationShipDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/24 23:03 5 | **/ 6 | package com.wip.model; 7 | 8 | /** 9 | * 文章关联信息表 10 | */ 11 | public class RelationShipDomain { 12 | 13 | /** 14 | * 文章主键 15 | */ 16 | private Integer cid; 17 | 18 | /** 19 | * 项目编号 20 | */ 21 | private Integer mid; 22 | 23 | public Integer getCid() { 24 | return cid; 25 | } 26 | 27 | public void setCid(Integer cid) { 28 | this.cid = cid; 29 | } 30 | 31 | public Integer getMid() { 32 | return mid; 33 | } 34 | 35 | public void setMid(Integer mid) { 36 | this.mid = mid; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/OptionDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/27 21:56 5 | **/ 6 | package com.wip.dao; 7 | 8 | import com.wip.model.OptionsDomain; 9 | import org.apache.ibatis.annotations.Mapper; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * 网站选项相关Dao接口 15 | */ 16 | @Mapper 17 | public interface OptionDao { 18 | 19 | /** 20 | * 获取网站全部信息 21 | * @return 22 | */ 23 | List getOptions(); 24 | 25 | /** 26 | * 更新网站配置 27 | * @param option 28 | */ 29 | void updateOptionByName(OptionsDomain option); 30 | 31 | /** 32 | * 通过名称网站配置 33 | * @param name 34 | * @return 35 | */ 36 | OptionsDomain getOptionByName(String name); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/log/LogService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 16:57 5 | **/ 6 | package com.wip.service.log; 7 | 8 | 9 | import com.github.pagehelper.PageInfo; 10 | import com.wip.model.LogDomain; 11 | 12 | /** 13 | * 日志相关Service接口 14 | */ 15 | public interface LogService { 16 | 17 | /** 18 | * 添加日志 19 | * @param action 触发动作 20 | * @param data 产生数据 21 | * @param ip 产生IP 22 | * @param authorId 产生人 23 | */ 24 | void addLog(String action, String data, String ip, Integer authorId); 25 | 26 | /** 27 | * 获取日志 28 | * @param pageNum 29 | * @param pageSize 30 | * @return 31 | */ 32 | PageInfo getLogs(int pageNum, int pageSize); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/user/UserService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 14:26 5 | **/ 6 | package com.wip.service.user; 7 | 8 | import com.wip.model.UserDomain; 9 | 10 | /** 11 | * 用户相关Service接口 12 | */ 13 | public interface UserService { 14 | 15 | /** 16 | * 用户登录 17 | * @param username 用户名 18 | * @param password 密码 19 | * @return 20 | */ 21 | UserDomain login(String username, String password); 22 | 23 | /** 24 | * 通过用户ID获取用户信息 25 | * @param uid 主键 26 | * @return 27 | */ 28 | UserDomain getUserInfoById(Integer uid); 29 | 30 | /** 31 | * 更改用户信息 32 | * @param user user对象 33 | * @return 34 | */ 35 | int updateUserInfo(UserDomain user); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.wip.dao; 2 | 3 | import com.wip.model.UserDomain; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | /** 8 | * 用户dao层接口 9 | */ 10 | @Mapper 11 | public interface UserDao { 12 | 13 | /** 14 | * 根据用户名密码获取用户信息 15 | * @param username 用户名 16 | * @param password 密码 17 | * @return 18 | */ 19 | UserDomain getUserInfoByCond(@Param("username") String username, @Param("password") String password); 20 | 21 | /** 22 | * 通过用户ID获取用户信息 23 | * @param uid 24 | * @return 25 | */ 26 | UserDomain getUserInfoById(Integer uid); 27 | 28 | /** 29 | * 更改用户信息 30 | * @param user 31 | * @return 32 | */ 33 | int updateUserInfo(UserDomain user); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/site/SiteService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/2 8:48 5 | **/ 6 | package com.wip.service.site; 7 | 8 | import com.wip.dto.StatisticsDto; 9 | import com.wip.model.CommentDomain; 10 | import com.wip.model.ContentDomain; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 网站相关Service接口 16 | */ 17 | public interface SiteService { 18 | 19 | /** 20 | * 获取评论列表 21 | * @param limit 22 | * @return 23 | */ 24 | List getComments(int limit); 25 | 26 | /** 27 | * 获取文章列表 28 | * @param limit 29 | * @return 30 | */ 31 | List getNewArticles(int limit); 32 | 33 | /** 34 | * 获取后台统计数 35 | * @return 36 | */ 37 | StatisticsDto getStatistics(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/option/OptionService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/27 21:55 5 | **/ 6 | package com.wip.service.option; 7 | 8 | import com.wip.model.OptionsDomain; 9 | 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * 网站选项相关Service接口 15 | */ 16 | public interface OptionService { 17 | 18 | /** 19 | * 获取全部网站配置 20 | * @return 21 | */ 22 | List getOptions(); 23 | 24 | /** 25 | * 保存系统设置 26 | * @param querys 27 | */ 28 | void saveOptions(Map querys); 29 | 30 | /** 31 | * 更新网站配置 32 | * @param s 33 | * @param s1 34 | */ 35 | void updateOptionByName(String name, String value); 36 | 37 | /** 38 | * 通过名称获取网站配置 39 | * @param site_record 40 | * @return 41 | */ 42 | OptionsDomain getOptionByName(String site_record); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/attach/AttAchService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/3 16:23 5 | **/ 6 | package com.wip.service.attach; 7 | 8 | import com.github.pagehelper.PageInfo; 9 | import com.wip.dto.AttAchDto; 10 | import com.wip.model.AttAchDomain; 11 | 12 | /** 13 | * 文件相关接口 14 | */ 15 | public interface AttAchService { 16 | 17 | /** 18 | * 添加单个附件信息 19 | * @param attAchDomain 20 | */ 21 | void addAttAch(AttAchDomain attAchDomain); 22 | 23 | /** 24 | * 获取所有的附件信息 25 | * @param pageNum 26 | * @param pageSize 27 | * @return 28 | */ 29 | PageInfo getAtts(int pageNum, int pageSize); 30 | 31 | /** 32 | * 通过ID获取附件信息 33 | * @param id 34 | * @return 35 | */ 36 | AttAchDto getAttAchById(Integer id); 37 | 38 | /** 39 | * 通过ID删除附件信息 40 | * @param id 41 | */ 42 | void deleteAttAch(Integer id); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/DateKit.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/26 15:48 5 | **/ 6 | package com.wip.utils; 7 | 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | 11 | /** 12 | * 时间工具类 13 | */ 14 | public class DateKit { 15 | 16 | 17 | 18 | public static String formatDateByUnixTime(long unixTime, String dateFormat) { 19 | return dateFormat(new Date(unixTime * 1000L), dateFormat); 20 | } 21 | 22 | public static String dateFormat(Date date, String dateFormat) { 23 | if (date != null) { 24 | SimpleDateFormat format = new SimpleDateFormat(dateFormat); 25 | return format.format(date); 26 | } 27 | return ""; 28 | } 29 | 30 | public static int getCurrentUnixTime() { 31 | return getUnixTimeByDate(new Date()); 32 | } 33 | 34 | public static int getUnixTimeByDate(Date date) { 35 | return (int)(date.getTime() / 1000L); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/OptionsDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/27 21:52 5 | **/ 6 | package com.wip.model; 7 | 8 | /** 9 | * 网站配置项 10 | */ 11 | public class OptionsDomain { 12 | 13 | /** 14 | * 名称 15 | */ 16 | private String name; 17 | /** 18 | * 内容 19 | */ 20 | private String value; 21 | 22 | /** 23 | * 描述 24 | */ 25 | private String description; 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public String getValue() { 36 | return value; 37 | } 38 | 39 | public void setValue(String value) { 40 | this.value = value; 41 | } 42 | 43 | public String getDescription() { 44 | return description; 45 | } 46 | 47 | public void setDescription(String description) { 48 | this.description = description; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/AttAchDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/3 16:25 5 | **/ 6 | package com.wip.dao; 7 | 8 | import com.wip.dto.AttAchDto; 9 | import com.wip.model.AttAchDomain; 10 | import org.apache.ibatis.annotations.Mapper; 11 | import org.apache.ibatis.annotations.Param; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * 文件相关Dao接口 17 | */ 18 | @Mapper 19 | public interface AttAchDao { 20 | 21 | /** 22 | * 添加单个附件文件 23 | * @param attAchDomain 24 | */ 25 | void addAttAch(AttAchDomain attAchDomain); 26 | 27 | /** 28 | * 获取所有的附件信息 29 | * @return 30 | */ 31 | List getAtts(); 32 | 33 | /** 34 | * 获取附件总数 35 | * @return 36 | */ 37 | Long getAttAchCount(); 38 | 39 | /** 40 | * 通过ID获取附件信息 41 | * @param id 42 | * @return 43 | */ 44 | AttAchDto getAttAchById(@Param("id") Integer id); 45 | 46 | /** 47 | * 通过ID删除附件信息 48 | * @param id 49 | */ 50 | void deleteAttAch(@Param("id") Integer id); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/wip/constant/Types.java: -------------------------------------------------------------------------------- 1 | package com.wip.constant; 2 | 3 | import com.wip.model.ContentDomain; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Ynw 8 | * DateTime: 2018/7/23 10:57 9 | **/ 10 | public enum Types { 11 | 12 | // 分类 13 | CATEGORY("category"), 14 | // 标签 15 | TAG("tag"), 16 | // 文章 17 | ARTICLE("post"), 18 | // csrf_token 19 | CSRF_TOKEN("csrf_token"), 20 | // 友情链接 21 | LINK("link"), 22 | // 评论 23 | COMMENTS_FREQUENCY("comments:frequency"), 24 | // 图片 25 | IMAGE("image"), 26 | // 文件 27 | FILE("file"), 28 | /** 29 | * 附件存在的URL,默认为网站地址,如集成第三方则为第三方CND域名 30 | */ 31 | // ATTACH_URL("attach_url"); 32 | ATTACH_URL("http://pb84kab39.bkt.clouddn.com/"); 33 | 34 | private String type; 35 | 36 | public java.lang.String getType() { 37 | return type; 38 | } 39 | 40 | public void setType(java.lang.String type) { 41 | this.type = type; 42 | } 43 | 44 | Types(java.lang.String type) { 45 | this.type = type; 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/main/java/com/wip/constant/WebConst.java: -------------------------------------------------------------------------------- 1 | package com.wip.constant; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * 系统常量 10 | */ 11 | @Component 12 | public class WebConst { 13 | 14 | 15 | /** 16 | * 一些网站配置 17 | */ 18 | public static Map initConfig = new HashMap<>(); 19 | 20 | 21 | /** 22 | * 用户登录session的key 23 | */ 24 | public static String LOGIN_SESSION_KEY = "login_user"; 25 | 26 | public static final String USER_IN_COOKIE = "S_L_ID"; 27 | 28 | 29 | /** 30 | * aes加密加盐 31 | */ 32 | public static String AES_SALT = "0123456789abcdef"; 33 | /** 34 | * 最大获取文章条数 35 | */ 36 | public static final int MAX_POSTS = 9999; 37 | 38 | /** 39 | * 文章标题最多可以输入的文字个数 40 | */ 41 | public static final int MAX_TITLE_COUNT = 200; 42 | 43 | /** 44 | * 文章内容最多可以输入的文字个数 45 | */ 46 | public static final int MAX_CONTENT_COUNT = 200000; 47 | 48 | /** 49 | * 点击次数超过铄和更新到数据库 50 | */ 51 | public static final int HIT_EXEED = 10; 52 | 53 | /** 54 | * 上传文件最大1M 55 | */ 56 | public static Integer MAX_FILE_SIZE = 1048576; 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/StatisticsDto.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/2 9:25 5 | **/ 6 | package com.wip.dto; 7 | 8 | /** 9 | * 后台统计对象 10 | */ 11 | public class StatisticsDto { 12 | 13 | /** 14 | * 文章数 15 | */ 16 | private Long articles; 17 | 18 | /** 19 | * 评论数 20 | */ 21 | private Long comments; 22 | 23 | /** 24 | * 链接数 25 | */ 26 | private Long links; 27 | 28 | /** 29 | * 文件数 30 | */ 31 | private Long attachs; 32 | 33 | public Long getArticles() { 34 | return articles; 35 | } 36 | 37 | public void setArticles(Long articles) { 38 | this.articles = articles; 39 | } 40 | 41 | public Long getComments() { 42 | return comments; 43 | } 44 | 45 | public void setComments(Long comments) { 46 | this.comments = comments; 47 | } 48 | 49 | public Long getLinks() { 50 | return links; 51 | } 52 | 53 | public void setLinks(Long links) { 54 | this.links = links; 55 | } 56 | 57 | public Long getAttachs() { 58 | return attachs; 59 | } 60 | 61 | public void setAttachs(Long attachs) { 62 | this.attachs = attachs; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/cond/CommentCond.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/31 22:39 5 | **/ 6 | package com.wip.dto.cond; 7 | 8 | /** 9 | * 评论的查找参数 10 | */ 11 | public class CommentCond { 12 | /** 13 | * 状态 14 | */ 15 | private String status; 16 | /** 17 | * 开始时间戳 18 | */ 19 | private Integer startTime; 20 | /** 21 | * 结束时间戳 22 | */ 23 | private Integer endTime; 24 | 25 | /** 26 | * 父评论编号 27 | */ 28 | private Integer parent; 29 | 30 | public String getStatus() { 31 | return status; 32 | } 33 | 34 | public void setStatus(String status) { 35 | this.status = status; 36 | } 37 | 38 | public Integer getStartTime() { 39 | return startTime; 40 | } 41 | 42 | public void setStartTime(Integer startTime) { 43 | this.startTime = startTime; 44 | } 45 | 46 | public Integer getEndTime() { 47 | return endTime; 48 | } 49 | 50 | public void setEndTime(Integer endTime) { 51 | this.endTime = endTime; 52 | } 53 | 54 | public Integer getParent() { 55 | return parent; 56 | } 57 | 58 | public void setParent(Integer parent) { 59 | this.parent = parent; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/resources/mapper/LogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | t_logs 7 | 8 | 9 | 10 | 11 | l.id, l.action, l.data, l.authorId, l.ip, l.created 12 | 13 | 14 | 15 | 16 | INSERT INTO 17 | 18 | 19 | action, data, authorId, ip, created, 20 | 21 | 22 | #{action, jdbcType=VARCHAR}, 23 | #{data, jdbcType=VARCHAR}, 24 | #{authorId, jdbcType=INTEGER}, 25 | #{ip, jdbcType=VARCHAR}, 26 | UNIX_TIMESTAMP(NOW()) 27 | 28 | 29 | 30 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/RelationShipDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/24 23:07 5 | **/ 6 | package com.wip.dao; 7 | 8 | import com.wip.model.RelationShipDomain; 9 | import org.apache.ibatis.annotations.Mapper; 10 | import org.apache.ibatis.annotations.Param; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 文章和项目关联表 16 | */ 17 | @Mapper 18 | public interface RelationShipDao { 19 | 20 | /** 21 | * 根据meta编号获取关联 22 | * @param mid 23 | * @return 24 | */ 25 | List getRelationShipByMid(Integer mid); 26 | 27 | /** 28 | * 根据meta编号删除关联 29 | * @param mid 30 | */ 31 | void deleteRelationShipByMid(Integer mid); 32 | 33 | /** 34 | * 获取数量 35 | * @param cid 36 | * @param mid 37 | * @return 38 | */ 39 | Long getCountById(@Param("cid") Integer cid, @Param("mid") Integer mid); 40 | 41 | /** 42 | * 添加 43 | * @param relationShip 44 | * @return 45 | */ 46 | int addRelationShip(RelationShipDomain relationShip); 47 | 48 | /** 49 | * 根据文章编号删除关联 50 | * @param cid 51 | */ 52 | void deleteRelationShipByCid(int cid); 53 | 54 | /** 55 | * 根据文章ID获取关联 56 | * @param cid 57 | */ 58 | List getRelationShipByCid(Integer cid); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/AdminCommons.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/24 23:26 5 | **/ 6 | package com.wip.utils; 7 | 8 | import com.wip.model.MetaDomain; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * 后台公共函数 14 | */ 15 | @Component 16 | public final class AdminCommons { 17 | 18 | 19 | /** 20 | * 判断category和cat的交集 21 | * @param category 22 | * @param cats 23 | * @return 24 | */ 25 | public static boolean exist_cat(MetaDomain category, String cats) { 26 | String[] arr = StringUtils.split(cats, ","); 27 | if (null != arr && arr.length > 0) { 28 | for (String c : arr) { 29 | if (c.trim().equals(category.getName())) { 30 | return true; 31 | } 32 | } 33 | } 34 | return false; 35 | } 36 | 37 | /** 38 | * 定义颜色样式数组 39 | */ 40 | private static final String[] COLORS = {"default", "primary", "success", "info", "warning", "danger", "inverse", "purple", "pink"}; 41 | 42 | /** 43 | * 随机样式 44 | * @return 45 | */ 46 | public static String rand_color() { 47 | int r = Tools.rand(0, COLORS.length - 1); 48 | return COLORS[r]; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/log/impl/LogServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 16:59 5 | **/ 6 | package com.wip.service.log.impl; 7 | 8 | import com.github.pagehelper.PageHelper; 9 | import com.github.pagehelper.PageInfo; 10 | import com.wip.dao.LogDao; 11 | import com.wip.model.LogDomain; 12 | import com.wip.service.log.LogService; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Service; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * 日志相关Service接口实现 20 | */ 21 | @Service 22 | public class LogServiceImpl implements LogService { 23 | 24 | 25 | @Autowired 26 | private LogDao logDao; 27 | 28 | 29 | @Override 30 | public void addLog(String action, String data, String ip, Integer authorId) { 31 | LogDomain logDomain = new LogDomain(); 32 | logDomain.setAuthorId(authorId); 33 | logDomain.setIp(ip); 34 | logDomain.setData(data); 35 | logDomain.setAction(action); 36 | logDao.addLog(logDomain); 37 | } 38 | 39 | @Override 40 | public PageInfo getLogs(int pageNum, int pageSize) { 41 | PageHelper.startPage(pageNum,pageSize); 42 | List logs = logDao.getLogs(); 43 | PageInfo pageInfo = new PageInfo<>(logs); 44 | return pageInfo; 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/comment/CommentService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/31 15:40 5 | **/ 6 | package com.wip.service.comment; 7 | 8 | import com.github.pagehelper.PageInfo; 9 | import com.wip.dto.cond.CommentCond; 10 | import com.wip.model.CommentDomain; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 评论相关Service接口 16 | */ 17 | public interface CommentService { 18 | 19 | /** 20 | * 添加评论 21 | * @param comments 22 | */ 23 | void addComment(CommentDomain comments); 24 | 25 | /** 26 | * 通过文章ID获取评论 27 | * @param cid 28 | * @return 29 | */ 30 | List getCommentsByCId(Integer cid); 31 | 32 | /** 33 | * 根据条件获取评论列表 34 | * @param commentCond 查询条件 35 | * @param pageNum 分页参数 第几页 36 | * @param pageSize 分页参数 每页条数 37 | * @return 38 | */ 39 | PageInfo getCommentsByCond(CommentCond commentCond, int pageNum, int pageSize); 40 | 41 | /** 42 | * 通过ID获取评论 43 | * @param coid 44 | * @return 45 | */ 46 | CommentDomain getCommentById(Integer coid); 47 | 48 | /** 49 | * 更新评论状态 50 | * @param coid 51 | * @param status 52 | */ 53 | void updateCommentStatus(Integer coid, String status); 54 | 55 | /** 56 | * 删除评论 57 | * @param id 58 | */ 59 | void deleteComment(Integer id); 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/BaseController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller; 2 | 3 | import com.wip.model.UserDomain; 4 | import com.wip.utils.MapCache; 5 | import com.wip.utils.TaleUtils; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | public abstract class BaseController { 10 | 11 | 12 | protected MapCache cache = MapCache.single(); 13 | 14 | 15 | public BaseController title(HttpServletRequest request, String title) { 16 | request.setAttribute("title", title); 17 | return this; 18 | } 19 | 20 | /** 21 | * 获取请求绑定的登录对象 22 | * @param request 23 | * @return 24 | */ 25 | public UserDomain user(HttpServletRequest request) { 26 | return TaleUtils.getLoginUser(request); 27 | } 28 | 29 | /** 30 | * 获取请求绑定登录用户Uid 31 | * @param request 32 | * @return 33 | */ 34 | public Integer getUid(HttpServletRequest request) { 35 | return this.user(request).getUid(); 36 | } 37 | 38 | 39 | /** 40 | * 数组转字符串 41 | * @param arr 数组 42 | * @return String 43 | */ 44 | public String join(String[] arr) { 45 | StringBuffer buffer = new StringBuffer(); 46 | String[] temp = arr; 47 | int length = arr.length; 48 | 49 | for (int i = 0; i < length; i++) { 50 | String item = temp[i]; 51 | buffer.append(",").append(item); 52 | } 53 | 54 | return buffer.length() > 0 ? buffer.substring(1) : buffer.toString(); 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/CommentDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/31 15:42 5 | **/ 6 | package com.wip.dao; 7 | 8 | import com.wip.dto.cond.CommentCond; 9 | import com.wip.model.CommentDomain; 10 | import org.apache.ibatis.annotations.Mapper; 11 | import org.apache.ibatis.annotations.Param; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * 评论相关Dao接口 17 | */ 18 | @Mapper 19 | public interface CommentDao { 20 | 21 | /** 22 | * 添加评论 23 | * @param comments 24 | */ 25 | void addComment(CommentDomain comments); 26 | 27 | /** 28 | * 根据文章ID获取评论 29 | * @param cid 30 | * @return 31 | */ 32 | List getCommentByCId(@Param("cid") Integer cid); 33 | 34 | 35 | /** 36 | * 删除评论 37 | * @param coid 38 | */ 39 | void deleteComment(@Param("coid") Integer coid); 40 | 41 | /** 42 | * 获取评论总数 43 | * @return 44 | */ 45 | Long getCommentCount(); 46 | 47 | /** 48 | * 根据条件获取评论列表 49 | * @param commentCond 50 | * @return 51 | */ 52 | List getCommentsByCond(CommentCond commentCond); 53 | 54 | /** 55 | * 通过ID获取评论 56 | * @param coid 57 | * @return 58 | */ 59 | CommentDomain getCommentById(@Param("coid") Integer coid); 60 | 61 | /** 62 | * 更新评论状态 63 | * @param coid 64 | * @param status 65 | */ 66 | void updateCommentStatus(@Param("coid") Integer coid, @Param("status") String status); 67 | } 68 | -------------------------------------------------------------------------------- /src/main/resources/mapper/OptionMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | t_options 8 | 9 | 10 | 11 | o.name, o.value, o.description 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | UPDATE 25 | 26 | 27 | 28 | value = #{value, jdbcType=VARCHAR} 29 | 30 | 31 | description = #{description, jdbcType=VARCHAR} 32 | 33 | 34 | WHERE 35 | name = #{name, jdbcType=VARCHAR} 36 | 37 | 38 | 39 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/ContentDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/25 16:50 5 | **/ 6 | package com.wip.dao; 7 | 8 | import com.wip.dto.cond.ContentCond; 9 | import com.wip.model.ContentDomain; 10 | import com.wip.model.RelationShipDomain; 11 | import org.apache.ibatis.annotations.Mapper; 12 | import org.apache.ibatis.annotations.Param; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * 文章相关Dao接口 18 | */ 19 | @Mapper 20 | public interface ContentDao { 21 | 22 | /** 23 | * 添加文章 24 | * @param contentDomain 25 | */ 26 | void addArticle(ContentDomain contentDomain); 27 | 28 | /** 29 | * 根据编号获取文章 30 | * @param cid 31 | * @return 32 | */ 33 | ContentDomain getArticleById(Integer cid); 34 | 35 | /** 36 | * 更新文章 37 | * @param contentDomain 38 | */ 39 | void updateArticleById(ContentDomain contentDomain); 40 | 41 | /** 42 | * 根据条件获取文章列表 43 | * @param contentCond 44 | * @return 45 | */ 46 | List getArticleByCond(ContentCond contentCond); 47 | 48 | /** 49 | * 删除文章 50 | * @param cid 51 | */ 52 | void deleteArticleById(Integer cid); 53 | 54 | /** 55 | * 获取文章总数 56 | * @return 57 | */ 58 | Long getArticleCount(); 59 | 60 | /** 61 | * 通过分类名获取文章 62 | * @param category 63 | * @return 64 | */ 65 | List getArticleByCategory(@Param("category") String category); 66 | 67 | /** 68 | * 通过标签获取文章 69 | * @param cid 70 | * @return 71 | */ 72 | List getArticleByTags(List cid); 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/IPKit.java: -------------------------------------------------------------------------------- 1 | package com.wip.utils; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | /** 8 | * ip工具类 9 | */ 10 | public class IPKit { 11 | 12 | /** 13 | * 获取请求IP地址 14 | * @param request 15 | * @return 16 | */ 17 | public static String getIpAddressByRequest(HttpServletRequest request) { 18 | String ip = request.getHeader("x-forwarded-for"); 19 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 20 | ip = request.getHeader("Proxy-Client-IP"); 21 | } 22 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 23 | ip = request.getHeader("WL-Proxy-Client-IP"); 24 | } 25 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 26 | ip = request.getRemoteAddr(); 27 | } 28 | return ip; 29 | } 30 | 31 | public static String getIpAddressByRequest1(HttpServletRequest request) { 32 | String ip = request.getHeader("X-Forwarded-For"); 33 | if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ 34 | //多次反向代理后会有多个ip值,第一个ip才是真实ip 35 | int index = ip.indexOf(","); 36 | if(index != -1){ 37 | return ip.substring(0,index); 38 | }else{ 39 | return ip; 40 | } 41 | } 42 | 43 | ip = request.getHeader("X-Real-IP"); 44 | if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ 45 | return ip; 46 | } 47 | return request.getRemoteAddr(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/article/ContentService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/25 16:48 5 | **/ 6 | package com.wip.service.article; 7 | 8 | import com.github.pagehelper.PageInfo; 9 | import com.wip.dto.cond.ContentCond; 10 | import com.wip.model.ContentDomain; 11 | import com.wip.model.MetaDomain; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * 文章相关Service接口 17 | */ 18 | public interface ContentService { 19 | 20 | /*** 21 | * 添加文章 22 | * @param contentDomain 23 | */ 24 | void addArticle(ContentDomain contentDomain); 25 | 26 | /** 27 | * 根据编号获取文章 28 | * @param cid 29 | * @return 30 | */ 31 | ContentDomain getArticleById(Integer cid); 32 | 33 | /** 34 | * 更新文章 35 | * @param contentDomain 36 | */ 37 | void updateArticleById(ContentDomain contentDomain); 38 | 39 | /** 40 | * 根据条件获取文章列表 41 | * @param contentCond 42 | * @param page 43 | * @param limit 44 | * @return 45 | */ 46 | PageInfo getArticlesByCond(ContentCond contentCond, int page, int limit); 47 | 48 | /** 49 | * 删除文章 50 | * @param cid 51 | */ 52 | void deleteArticleById(Integer cid); 53 | 54 | /** 55 | * 添加文章点击量 56 | * @param content 57 | */ 58 | void updateContentByCid(ContentDomain content); 59 | 60 | /** 61 | * 通过分类获取文章 62 | * @param category 63 | * @return 64 | */ 65 | List getArticleByCategory(String category); 66 | 67 | /** 68 | * 通过标签获取文章 69 | * @param tags 70 | * @return 71 | */ 72 | List getArticleByTags(MetaDomain tags); 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/AttAchDto.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/3 16:31 5 | **/ 6 | package com.wip.dto; 7 | 8 | public class AttAchDto extends BaseDto { 9 | /** 10 | * 主键编号 11 | */ 12 | private Integer id; 13 | 14 | /** 15 | * 文件名称 16 | */ 17 | private String fname; 18 | 19 | /** 20 | * 文件类型 21 | */ 22 | private String ftype; 23 | 24 | /** 25 | * 文件的地址 26 | */ 27 | private String fkey; 28 | 29 | /** 30 | * 上传人的ID 31 | */ 32 | private Integer authorId; 33 | 34 | /** 35 | * 创建的时间戳 36 | */ 37 | private Integer created; 38 | 39 | public Integer getId() { 40 | return id; 41 | } 42 | 43 | public void setId(Integer id) { 44 | this.id = id; 45 | } 46 | 47 | public String getFname() { 48 | return fname; 49 | } 50 | 51 | public void setFname(String fname) { 52 | this.fname = fname; 53 | } 54 | 55 | public String getFtype() { 56 | return ftype; 57 | } 58 | 59 | public void setFtype(String ftype) { 60 | this.ftype = ftype; 61 | } 62 | 63 | public String getFkey() { 64 | return fkey; 65 | } 66 | 67 | public void setFkey(String fkey) { 68 | this.fkey = fkey; 69 | } 70 | 71 | public Integer getAuthorId() { 72 | return authorId; 73 | } 74 | 75 | public void setAuthorId(Integer authorId) { 76 | this.authorId = authorId; 77 | } 78 | 79 | public Integer getCreated() { 80 | return created; 81 | } 82 | 83 | public void setCreated(Integer created) { 84 | this.created = created; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dao/MetaDao.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 17:03 5 | **/ 6 | package com.wip.dao; 7 | 8 | import com.wip.dto.MetaDto; 9 | import com.wip.dto.cond.MetaCond; 10 | import com.wip.model.MetaDomain; 11 | import org.apache.ibatis.annotations.Mapper; 12 | import org.apache.ibatis.annotations.Param; 13 | 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * 项目相关Dao接口 19 | */ 20 | @Mapper 21 | public interface MetaDao { 22 | 23 | /** 24 | * 添加项目 25 | * @param meta 项目对象 26 | * @return 27 | */ 28 | int addMeta(MetaDomain meta); 29 | 30 | /** 31 | * 更新项目 32 | * @param meta 项目对象 33 | * @return 34 | */ 35 | int updateMeta(MetaDomain meta); 36 | 37 | /** 38 | * 根据条件查询 39 | * @param metaCond 40 | * @return 41 | */ 42 | List getMetasByCond(MetaCond metaCond); 43 | 44 | /** 45 | * 根据ID获取项目 46 | * @param mid 47 | * @return 48 | */ 49 | MetaDomain getMetaById(@Param("mid") Integer mid); 50 | 51 | /** 52 | * 根据sql查询 53 | * @param parMap 54 | * @return 55 | */ 56 | List selectFromSql(Map parMap); 57 | 58 | /** 59 | * 删除项目 60 | * @param mid 61 | */ 62 | void deleteMetaById(Integer mid); 63 | 64 | /** 65 | * 根据类型获取meta数量 66 | * @param type 67 | * @return 68 | */ 69 | Long getMetasCountByType(@Param("type") String type); 70 | 71 | /** 72 | * 通过Meta名查找Meta项目 73 | * @param type 74 | * @param name 75 | * @return 76 | */ 77 | MetaDomain getMetaByName(@Param("type") String type, @Param("name") String name); 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/AttAchDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/3 16:18 5 | **/ 6 | package com.wip.model; 7 | 8 | /** 9 | * 网站图片文件相关表 10 | */ 11 | public class AttAchDomain { 12 | 13 | /** 14 | * 主键编号 15 | */ 16 | private Integer id; 17 | 18 | /** 19 | * 文件名称 20 | */ 21 | private String fname; 22 | 23 | /** 24 | * 文件类型 25 | */ 26 | private String ftype; 27 | 28 | /** 29 | * 文件的地址 30 | */ 31 | private String fkey; 32 | 33 | /** 34 | * 上传人的ID 35 | */ 36 | private Integer authorId; 37 | 38 | /** 39 | * 创建的时间戳 40 | */ 41 | private Integer created; 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 getFname() { 52 | return fname; 53 | } 54 | 55 | public void setFname(String fname) { 56 | this.fname = fname; 57 | } 58 | 59 | public String getFtype() { 60 | return ftype; 61 | } 62 | 63 | public void setFtype(String ftype) { 64 | this.ftype = ftype; 65 | } 66 | 67 | public String getFkey() { 68 | return fkey; 69 | } 70 | 71 | public void setFkey(String fkey) { 72 | this.fkey = fkey; 73 | } 74 | 75 | public Integer getAuthorId() { 76 | return authorId; 77 | } 78 | 79 | public void setAuthorId(Integer authorId) { 80 | this.authorId = authorId; 81 | } 82 | 83 | public Integer getCreated() { 84 | return created; 85 | } 86 | 87 | public void setCreated(Integer created) { 88 | this.created = created; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/APIResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 13:50 5 | **/ 6 | package com.wip.utils; 7 | 8 | public class APIResponse { 9 | 10 | private static final String CODE_SUCCESS = "success"; 11 | 12 | private static final String CODE_FAIL = "fail"; 13 | 14 | private String code; 15 | private T data; 16 | private String msg; 17 | 18 | public APIResponse() { 19 | 20 | } 21 | 22 | public APIResponse(String code) { 23 | this.code = code; 24 | } 25 | 26 | public APIResponse(String code, T data) { 27 | this.code = code; 28 | this.data = data; 29 | } 30 | 31 | public APIResponse(String code, String msg) { 32 | this.code = code; 33 | this.msg = msg; 34 | } 35 | 36 | public static APIResponse success() { 37 | return new APIResponse(CODE_SUCCESS); 38 | } 39 | 40 | public static APIResponse success(Object data) { 41 | return new APIResponse(CODE_SUCCESS, data); 42 | } 43 | 44 | public static APIResponse fail(String msg) { 45 | return new APIResponse(CODE_FAIL,msg); 46 | } 47 | 48 | public static APIResponse widthCode(String errorCode) { 49 | return new APIResponse(errorCode); 50 | } 51 | 52 | public String getCode() { 53 | return code; 54 | } 55 | 56 | public void setCode(String code) { 57 | this.code = code; 58 | } 59 | 60 | public T getData() { 61 | return data; 62 | } 63 | 64 | public void setData(T data) { 65 | this.data = data; 66 | } 67 | 68 | public String getMsg() { 69 | return msg; 70 | } 71 | 72 | public void setMsg(String msg) { 73 | this.msg = msg; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/Tools.java: -------------------------------------------------------------------------------- 1 | package com.wip.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.util.Random; 9 | 10 | public class Tools { 11 | 12 | private static final Random random = new Random(); 13 | 14 | 15 | public static String enAes(String data, String key) throws Exception { 16 | Cipher cipher = Cipher.getInstance("AES"); 17 | SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"),"ASE"); 18 | cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 19 | byte[] encryptedBytes = cipher.doFinal(data.getBytes()); 20 | return new BASE64Encoder().encode(encryptedBytes); 21 | } 22 | 23 | public static String deAes(String data, String key) throws Exception { 24 | Cipher cipher = Cipher.getInstance("AES"); 25 | SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); 26 | cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 27 | byte[] cipherTextBytes = new BASE64Decoder().decodeBuffer(data); 28 | byte[] decValue = cipher.doFinal(cipherTextBytes); 29 | return new String(decValue); 30 | } 31 | 32 | /** 33 | * 判断字符串是否为数字和有正确的值 34 | * @param str 35 | * @return 36 | */ 37 | public static boolean isNumber(String str) { 38 | if (null != str && 0 != str.trim().length() && str.matches("\\d*")) { 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | /** 45 | * 随机数 46 | * @param min 47 | * @param max 48 | * @return 49 | */ 50 | public static int rand(int min, int max) { 51 | return random.nextInt(max) % (max - min + 1) + min; 52 | } 53 | 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8122 3 | spring: 4 | datasource: 5 | name: mysql_test 6 | type: com.alibaba.druid.pool.DruidDataSource 7 | #druid相关配置 8 | druid: 9 | #监控统计拦截的filters 10 | filters: stat 11 | driver-class-name: com.mysql.jdbc.Driver 12 | #基本属性 13 | url: jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true 14 | username: root 15 | password: root 16 | #配置初始化大小/最小/最大 17 | initial-size: 1 18 | min-idle: 1 19 | max-active: 20 20 | #获取连接等待超时时间 21 | max-wait: 60000 22 | #间隔多久进行一次检测,检测需要关闭的空闲连接 23 | time-between-eviction-runs-millis: 60000 24 | #一个连接在池中最小生存的时间 25 | min-evictable-idle-time-millis: 300000 26 | validation-query: SELECT 'x' 27 | test-while-idle: true 28 | test-on-borrow: false 29 | test-on-return: false 30 | #打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false 31 | pool-prepared-statements: false 32 | max-pool-prepared-statement-per-connection-size: 20 33 | thymeleaf: 34 | prefix: classpath:/templates/ 35 | check-template-location: true 36 | suffix: .html 37 | encoding: utf-8 38 | cache: false 39 | 40 | aop: 41 | auto: true 42 | proxy-target-class: true 43 | 44 | servlet: 45 | multipart: 46 | max-file-size: 10Mb 47 | max-request-size: 100Mb 48 | 49 | 50 | 51 | logging: 52 | level: 53 | com.wip.dao: DEBUG 54 | 55 | 56 | 57 | mybatis: 58 | mapper-locations: classpath:mapper/*.xml 59 | type-aliases-package: com.wip.model 60 | 61 | swagger: 62 | show: true 63 | #分页 64 | pagehelper: 65 | helper-dialect: mysql 66 | reasonable: true 67 | support-methods-arguments: true 68 | params: count=countSql 69 | retrunPageInfo: check 70 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/user/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 14:27 5 | **/ 6 | package com.wip.service.user.impl; 7 | 8 | import com.wip.constant.ErrorConstant; 9 | import com.wip.dao.UserDao; 10 | import com.wip.exception.BusinessException; 11 | import com.wip.model.UserDomain; 12 | import com.wip.service.user.UserService; 13 | import com.wip.utils.APIResponse; 14 | import com.wip.utils.TaleUtils; 15 | import org.apache.commons.lang3.StringUtils; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Service; 18 | import org.springframework.transaction.annotation.Transactional; 19 | 20 | /** 21 | * 用户相关Service接口实现 22 | */ 23 | @Service 24 | public class UserServiceImpl implements UserService { 25 | 26 | @Autowired 27 | private UserDao userDao;//这里会报错,但是并不影响 28 | 29 | 30 | @Override 31 | public UserDomain login(String username, String password) { 32 | 33 | if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) 34 | throw BusinessException.withErrorCode(ErrorConstant.Auth.USERNAME_PASSWORD_IS_EMPTY); 35 | 36 | String pwd = TaleUtils.MD5encode(username + password); 37 | UserDomain user = userDao.getUserInfoByCond(username,pwd); 38 | if (null == user) 39 | throw BusinessException.withErrorCode(ErrorConstant.Auth.USERNAME_PASSWORD_ERROR); 40 | return user; 41 | } 42 | 43 | @Override 44 | public UserDomain getUserInfoById(Integer uid) { 45 | return userDao.getUserInfoById(uid); 46 | } 47 | 48 | // 开启事务 49 | @Transactional 50 | @Override 51 | public int updateUserInfo(UserDomain user) { 52 | if (null == user.getUid()) 53 | throw BusinessException.withErrorCode("用户编号不能为空"); 54 | return userDao.updateUserInfo(user); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/LogDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 17:00 5 | **/ 6 | package com.wip.model; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 日志表 12 | */ 13 | public class LogDomain implements Serializable { 14 | 15 | private static final long serialVersionUID = 1L; 16 | 17 | /** 18 | * 日志主键 19 | */ 20 | private Integer id; 21 | 22 | /** 23 | * 产生的动作 24 | */ 25 | private String action; 26 | 27 | /** 28 | * 产生的数据 29 | */ 30 | private String data; 31 | 32 | /** 33 | * 发生人id 34 | */ 35 | private Integer authorId; 36 | 37 | /** 38 | * 日志产生的IP 39 | */ 40 | private String ip; 41 | 42 | /** 43 | * 日志创建时间 44 | */ 45 | private Integer created; 46 | 47 | public static long getSerialVersionUID() { 48 | return serialVersionUID; 49 | } 50 | 51 | public Integer getId() { 52 | return id; 53 | } 54 | 55 | public void setId(Integer id) { 56 | this.id = id; 57 | } 58 | 59 | public String getAction() { 60 | return action; 61 | } 62 | 63 | public void setAction(String action) { 64 | this.action = action; 65 | } 66 | 67 | public String getData() { 68 | return data; 69 | } 70 | 71 | public void setData(String data) { 72 | this.data = data; 73 | } 74 | 75 | public Integer getAuthorId() { 76 | return authorId; 77 | } 78 | 79 | public void setAuthorId(Integer authorId) { 80 | this.authorId = authorId; 81 | } 82 | 83 | public String getIp() { 84 | return ip; 85 | } 86 | 87 | public void setIp(String ip) { 88 | this.ip = ip; 89 | } 90 | 91 | public Integer getCreated() { 92 | return created; 93 | } 94 | 95 | public void setCreated(Integer created) { 96 | this.created = created; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | t_users 8 | 9 | 10 | 11 | uid,username,password,email,homeUrl,screenName,created,activated,logged,groupName 12 | 13 | 14 | 15 | 30 | 31 | 39 | 40 | 41 | UPDATE 42 | 43 | 44 | 45 | password = #{password, jdbcType=VARCHAR}, 46 | 47 | 48 | screenName = #{screenName, jdbcType=VARCHAR}, 49 | 50 | 51 | email = #{email, jdbcType=VARCHAR} 52 | 53 | 54 | WHERE 55 | uid = #{uid,jdbcType=INTEGER} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/meta/MetaService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 16:42 5 | **/ 6 | package com.wip.service.meta; 7 | 8 | import com.wip.dto.MetaDto; 9 | import com.wip.dto.cond.MetaCond; 10 | import com.wip.model.MetaDomain; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 项目相关Service接口 16 | */ 17 | public interface MetaService { 18 | 19 | /** 20 | * 添加 21 | * @param type 项目类型 22 | * @param name 项目名称 23 | * @param mid 项目ID 24 | */ 25 | void saveMeta(String type, String name, Integer mid); 26 | 27 | /** 28 | * 根据类型查询项目列表,带项目正面的文章数 29 | * @param type 项目类型 30 | * @param orderBy 排序字段 31 | * @param limit 限制条数 32 | * @return 33 | */ 34 | List getMetaList(String type, String orderBy, int limit); 35 | 36 | /** 37 | * 添加或者更新 38 | * @param cid 39 | * @param name 40 | * @param type 41 | */ 42 | void saveOrUpdate(Integer cid, String name, String type); 43 | 44 | /** 45 | * 批量添加 46 | * @param cid 47 | * @param names 48 | * @param type 49 | */ 50 | void addMetas(Integer cid, String names, String type); 51 | 52 | /** 53 | * 删除项目 54 | * @param mid 55 | */ 56 | void deleteMetaById(Integer mid); 57 | 58 | /** 59 | * 获取所有项目 60 | * @param metaCond 查询条件 61 | * @return 62 | */ 63 | List getMetas(MetaCond metaCond); 64 | 65 | /** 66 | * 添加项目 67 | * @param meta 68 | */ 69 | void addMea(MetaDomain meta); 70 | 71 | /** 72 | * 更新项目 73 | * @param meta 74 | */ 75 | void updateMeta(MetaDomain meta); 76 | 77 | /** 78 | * 通过类型获取项目总数 79 | * @param type 80 | * @return 81 | */ 82 | Long getMetasCountByType(String type); 83 | 84 | /** 85 | * 通过Meta名查找Meta项目 86 | * @param type 87 | * @param name 88 | * @return 89 | */ 90 | MetaDomain getMetaByName(String type, String name); 91 | } 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **完整代码收费 可以加qq 931708230 或者加微信ynwwxid 咨询** 2 | 3 | **接毕业设计和论文** 4 | 5 | **博客地址:[https://blog.csdn.net/2303_76227485/article/details/128661927](https://blog.csdn.net/2303_76227485/article/details/128661927)** 6 | 7 | **视频演示:[https://space.bilibili.com/384537280](https://space.bilibili.com/384537280)** 8 | 9 | **毕业设计所有选题地址:[https://github.com/ynwynw/allProject](https://github.com/ynwynw/allProject)** 10 | 11 | ## 基于SpringBoot的个人博客管理系统 12 | 13 | ## 一、系统介绍 14 | 15 | 前台: 16 | - 文章列表、文章详情。 17 | - 评论。 18 | - 分类查看。 19 | 20 | 后台管理: 21 | - 文章统计、评论统计、附件统计、日志查看 22 | - 文章发布 23 | - 评论管理 24 | - 文章管理 25 | - 分类标签管理 26 | - 文件管理 27 | 28 | ## 二、所用技术 29 | 30 | ### 后端 31 | * 核心框架:SpringBoot 32 | * 持久层框架:MyBatis 33 | * 模板框架:Thymeleaf 34 | * 分页插件:PageHelper 35 | * 缓存框架:Ehcache 36 | * Markdown:Commonmark 37 | 38 | ### 前端 39 | * JS框架:Jquery 40 | * CSS框架:Bootstrap 41 | * 富文本编辑器:editor.md 42 | * 文件上传:dropzone 43 | * 弹框插件:sweetalert 44 | 45 | ### 第三方 46 | * 七牛云(文件上传)/本地文件上传 47 | * 百度统计 48 | 49 | 50 | ## 三、环境介绍 51 | 52 | 基础环境 :IDEA/eclipse, maven3.x, JDK 1.8 , Mysql, 53 | 54 | 源码+数据库脚本 55 | 56 | 所有项目以及源代码本人均调试运行无问题 可支持远程调试运行 57 | 58 | ## 四、页面截图 59 | 60 | ![contents](./picture/picture1.png) 61 | 62 | ![contents](./picture/picture2.png) 63 | 64 | ![contents](./picture/picture3.png) 65 | 66 | ![contents](./picture/picture4.png) 67 | 68 | ![contents](./picture/picture5.png) 69 | 70 | ![contents](./picture/picture6.png) 71 | 72 | ![contents](./picture/picture7.png) 73 | 74 | ![contents](./picture/picture8.png) 75 | 76 | ![contents](./picture/picture9.png) 77 | 78 | ![contents](./picture/picture10.png) 79 | 80 | ![contents](./picture/picture11.png) 81 | 82 | ![contents](./picture/picture12.png) 83 | 84 | 85 | ## 五、浏览地址 86 | 87 | 前端访问地址:http://localhost:8122 88 | 89 | 后台访问地址:http://localhost:8122/admin 用户名:admin 密码:123456 90 | 91 | ## 六、安装教程 92 | 93 | 下载源码,执行sql文件,然后修改application-dev.yml文件中连接数据库的用户名、密码。运行项目即可。 94 | 95 | **需要完整代码可以加qq 931708230 或者加微信 ynwwxid** 96 | 97 | **需要完整代码可以加qq 931708230 或者加微信 ynwwxid** 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/main/java/com/wip/constant/ErrorConstant.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 14:47 5 | **/ 6 | package com.wip.constant; 7 | 8 | /** 9 | * 错误常量处理接口 10 | */ 11 | public interface ErrorConstant { 12 | 13 | interface Common { 14 | static final String PARAM_IS_EMPTY = "参数为空"; 15 | static final String INVALID_PARAM = "无效的参数"; 16 | static final String CAN_NOT_FIND_PARAM_TO_CONTIUNE = "找不到参数继续运行"; 17 | } 18 | 19 | interface Article { 20 | static final String UPDATE_ARTICLE_FAIL = "更新文章失败"; 21 | static final String ADD_NEW_ARTICLE_FAIL = "添加文章失败"; 22 | static final String DELETE_ARTICLE_ERROR = "删除文章失败"; 23 | static final String TITLE_IS_TOO_LONG = "文章标题过长"; 24 | static final String TITLE_CAN_NOT_EMPTY = "文章标题不能为空"; 25 | static final String CONTENT_CAN_NOT_EMPTY = "文章内容不能为空"; 26 | static final String CONTENT_IS_TOO_LONG = "文章字数超过限制"; 27 | 28 | } 29 | 30 | interface Att { 31 | static final String ADD_NEW_ATT_FAIL = "添加附件信息失败"; 32 | static final String UPDATE_ATT_FAIL = "更新附件信息失败"; 33 | static final String DELETE_ATT_FAIL = "删除附件信息失败"; 34 | static final String UPLOAD_FILE_FAIL = "上传附件失败"; 35 | } 36 | 37 | interface Comment { 38 | static final String ADD_NEW_COMMENT_FAIL = "添加评论失败"; 39 | static final String UPDATE_COMMENT_FAIL = "更新评论失败"; 40 | static final String DELETE_COMMENT_FAIL = "删除评论失败"; 41 | static final String COMMENT_NOT_EXIST = "评论不存在"; 42 | } 43 | 44 | interface Option { 45 | static final String DELETE_OPTION_FAIL = "删除配置失败"; 46 | static final String UPDATE_OPTION_FAIL = "更新配置失败"; 47 | } 48 | 49 | interface Meta { 50 | static final String ADD_META_FAIL = "添加项目信息失败"; 51 | static final String UPDATE_META_FAIL = "更新项目信息失败"; 52 | static final String DELETE_META_FAIL = "删除项目信息失败"; 53 | static final String NOT_ONE_RESULT = "获取的项目的数量不止一个"; 54 | static final String META_IS_EXIST = "该项目已经存在"; 55 | } 56 | 57 | interface Auth { 58 | static final String USERNAME_PASSWORD_IS_EMPTY = "用户名和密码不可为空"; 59 | static final String USERNAME_PASSWORD_ERROR = "用户名不存在或密码错误"; 60 | static final String NOT_LOGIN = "用户未登录"; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/wip/dto/cond/ContentCond.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/26 15:15 5 | **/ 6 | package com.wip.dto.cond; 7 | 8 | /** 9 | * 文章查询条件 10 | */ 11 | public class ContentCond { 12 | /** 13 | * 标签 14 | */ 15 | private String tag; 16 | /** 17 | * 类别 18 | */ 19 | private String category; 20 | /** 21 | * 状态 22 | */ 23 | private String status; 24 | /** 25 | * 标题 26 | */ 27 | private String title; 28 | /** 29 | * 内容匹配 30 | */ 31 | private String content; 32 | /** 33 | * 文章类型 34 | */ 35 | private String type; 36 | /** 37 | * 开始时间戳 38 | */ 39 | private Integer startTime; 40 | /** 41 | * 结束时间戳 42 | */ 43 | private Integer endTime; 44 | 45 | public String getTag() { 46 | return tag; 47 | } 48 | 49 | public void setTag(String tag) { 50 | this.tag = tag; 51 | } 52 | 53 | public String getCategory() { 54 | return category; 55 | } 56 | 57 | public void setCategory(String category) { 58 | this.category = category; 59 | } 60 | 61 | public String getStatus() { 62 | return status; 63 | } 64 | 65 | public void setStatus(String status) { 66 | this.status = status; 67 | } 68 | 69 | public String getTitle() { 70 | return title; 71 | } 72 | 73 | public void setTitle(String title) { 74 | this.title = title; 75 | } 76 | 77 | public String getContent() { 78 | return content; 79 | } 80 | 81 | public void setContent(String content) { 82 | this.content = content; 83 | } 84 | 85 | public String getType() { 86 | return type; 87 | } 88 | 89 | public void setType(String type) { 90 | this.type = type; 91 | } 92 | 93 | public Integer getStartTime() { 94 | return startTime; 95 | } 96 | 97 | public void setStartTime(Integer startTime) { 98 | this.startTime = startTime; 99 | } 100 | 101 | public Integer getEndTime() { 102 | return endTime; 103 | } 104 | 105 | public void setEndTime(Integer endTime) { 106 | this.endTime = endTime; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/attach/impl/AttAchServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/3 16:24 5 | **/ 6 | package com.wip.service.attach.impl; 7 | 8 | import com.github.pagehelper.PageHelper; 9 | import com.github.pagehelper.PageInfo; 10 | import com.wip.constant.ErrorConstant; 11 | import com.wip.dao.AttAchDao; 12 | import com.wip.dto.AttAchDto; 13 | import com.wip.exception.BusinessException; 14 | import com.wip.model.AttAchDomain; 15 | import com.wip.service.attach.AttAchService; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.cache.annotation.CacheEvict; 18 | import org.springframework.cache.annotation.Cacheable; 19 | import org.springframework.stereotype.Service; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * 文件接口实现 25 | */ 26 | @Service 27 | public class AttAchServiceImpl implements AttAchService { 28 | 29 | @Autowired 30 | private AttAchDao attAchDao; 31 | 32 | @Override 33 | @CacheEvict(value = {"attCaches", "attCache"}, allEntries = true, beforeInvocation = true) 34 | public void addAttAch(AttAchDomain attAchDomain) { 35 | if (null == attAchDomain) 36 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 37 | attAchDao.addAttAch(attAchDomain); 38 | } 39 | 40 | @Override 41 | @Cacheable(value = "attCaches", key = "'atts' + #p0") 42 | public PageInfo getAtts(int pageNum, int pageSize) { 43 | PageHelper.startPage(pageNum, pageSize); 44 | List atts = attAchDao.getAtts(); 45 | PageInfo pageInfo = new PageInfo<>(atts); 46 | return pageInfo; 47 | } 48 | 49 | @Override 50 | @Cacheable(value = "attCaches", key = "'attAchByid' + #p0") 51 | public AttAchDto getAttAchById(Integer id) { 52 | if (null == id) 53 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 54 | return attAchDao.getAttAchById(id); 55 | } 56 | 57 | @Override 58 | @CacheEvict(value = {"attCaches", "attCache"}, allEntries = true, beforeInvocation = true) 59 | public void deleteAttAch(Integer id) { 60 | if (null == id) 61 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 62 | attAchDao.deleteAttAch(id); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/resources/mapper/RelationShipMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | t_relationships 7 | 8 | 9 | 10 | 11 | rs.cid, rs.mid 12 | 13 | 14 | 15 | 23 | 24 | 25 | 26 | 27 | 28 | DELETE FROM 29 | 30 | WHERE 31 | mid = #{mid, jdbcType=INTEGER} 32 | 33 | 34 | 35 | DELETE FROM 36 | 37 | WHERE 38 | cid = #{cid, jdbcType=INTEGER} 39 | 40 | 41 | 42 | 52 | 53 | 54 | 55 | INSERT INTO 56 | 57 | 58 | cid, mid, 59 | 60 | 61 | #{cid, jdbcType=INTEGER}, 62 | #{mid, jdbcType=INTEGER} 63 | 64 | 65 | 66 | 67 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/option/impl/OptionServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Administrator 4 | * DateTime: 2018/7/27 21:55 5 | **/ 6 | package com.wip.service.option.impl; 7 | 8 | import com.wip.constant.ErrorConstant; 9 | import com.wip.dao.OptionDao; 10 | import com.wip.exception.BusinessException; 11 | import com.wip.model.OptionsDomain; 12 | import com.wip.service.option.OptionService; 13 | import org.apache.commons.lang3.StringUtils; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.cache.annotation.CacheEvict; 16 | import org.springframework.cache.annotation.Cacheable; 17 | import org.springframework.stereotype.Service; 18 | import org.springframework.transaction.annotation.Transactional; 19 | 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | @Service 24 | public class OptionServiceImpl implements OptionService { 25 | 26 | @Autowired 27 | private OptionDao optionDao; 28 | 29 | @Override 30 | @Cacheable(value = "optionsCache", key = "'options_'") 31 | public List getOptions() { 32 | return optionDao.getOptions(); 33 | } 34 | 35 | @Override 36 | @Transactional 37 | @CacheEvict(value = {"optionsCache", "optionCache"}, allEntries = true, beforeInvocation = true) 38 | public void saveOptions(Map options) { 39 | if (null != options && !options.isEmpty()) { 40 | options.forEach(this::updateOptionByName); 41 | } 42 | } 43 | 44 | @Override 45 | @Transactional 46 | @CacheEvict(value = {"optionsCache", "optionCache"}, allEntries = true, beforeInvocation = true) 47 | public void updateOptionByName(String name, String value) { 48 | if (StringUtils.isBlank(name)) 49 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 50 | OptionsDomain option = new OptionsDomain(); 51 | option.setName(name); 52 | option.setValue(value); 53 | optionDao.updateOptionByName(option); 54 | } 55 | 56 | @Override 57 | @Cacheable(value = "optionCache", key = "'optionByname+' + #p0") 58 | public OptionsDomain getOptionByName(String name) { 59 | if (StringUtils.isBlank(name)) 60 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 61 | return optionDao.getOptionByName(name); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/MetaDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 16:36 5 | **/ 6 | package com.wip.model; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 项目表 12 | */ 13 | public class MetaDomain implements Serializable { 14 | private static final long serialVersionUID = 1L; 15 | 16 | /** 17 | * 项目主键 18 | */ 19 | private Integer mid; 20 | /** 21 | * 名称 22 | */ 23 | private String name; 24 | 25 | /** 26 | * 项目缩略名 27 | */ 28 | private String slug; 29 | 30 | /** 31 | * 项目类型 32 | */ 33 | private String type; 34 | 35 | /** 36 | * 对应的文章类型 37 | */ 38 | private String contentType; 39 | 40 | /** 41 | * 选项描述 42 | */ 43 | private String description; 44 | 45 | /** 46 | * 项目排序 47 | */ 48 | private Integer sort; 49 | 50 | private Integer parent; 51 | 52 | public static long getSerialVersionUID() { 53 | return serialVersionUID; 54 | } 55 | 56 | public Integer getMid() { 57 | return mid; 58 | } 59 | 60 | public void setMid(Integer mid) { 61 | this.mid = mid; 62 | } 63 | 64 | public String getName() { 65 | return name; 66 | } 67 | 68 | public void setName(String name) { 69 | this.name = name; 70 | } 71 | 72 | public String getSlug() { 73 | return slug; 74 | } 75 | 76 | public void setSlug(String slug) { 77 | this.slug = slug; 78 | } 79 | 80 | public String getType() { 81 | return type; 82 | } 83 | 84 | public void setType(String type) { 85 | this.type = type; 86 | } 87 | 88 | public String getContentType() { 89 | return contentType; 90 | } 91 | 92 | public void setContentType(String contentType) { 93 | this.contentType = contentType; 94 | } 95 | 96 | public String getDescription() { 97 | return description; 98 | } 99 | 100 | public void setDescription(String description) { 101 | this.description = description; 102 | } 103 | 104 | public Integer getSort() { 105 | return sort; 106 | } 107 | 108 | public void setSort(Integer sort) { 109 | this.sort = sort; 110 | } 111 | 112 | public Integer getParent() { 113 | return parent; 114 | } 115 | 116 | public void setParent(Integer parent) { 117 | this.parent = parent; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/UserDomain.java: -------------------------------------------------------------------------------- 1 | package com.wip.model; 2 | 3 | /** 4 | * 用户表 5 | */ 6 | public class UserDomain { 7 | 8 | /** 主键编号 */ 9 | private Integer uid; 10 | /** 用户名 */ 11 | private String username; 12 | /** 密码 */ 13 | private String password; 14 | /** email */ 15 | private String email; 16 | /** 主页地址 */ 17 | private String homeUrl; 18 | /** 用户显示的名称 */ 19 | private String screenName; 20 | /** 用户注册时的GMT unix时间戳 */ 21 | private Integer created; 22 | /** 最后活动时间 */ 23 | private Integer activated; 24 | /** 上次登录最后活跃时间 */ 25 | private Integer logged; 26 | /** 用户组 */ 27 | private String groupName; 28 | 29 | public Integer getUid() { 30 | return uid; 31 | } 32 | 33 | public void setUid(Integer uid) { 34 | this.uid = uid; 35 | } 36 | 37 | public String getUsername() { 38 | return username; 39 | } 40 | 41 | public void setUsername(String username) { 42 | this.username = username; 43 | } 44 | 45 | public String getPassword() { 46 | return password; 47 | } 48 | 49 | public void setPassword(String password) { 50 | this.password = password; 51 | } 52 | 53 | public String getEmail() { 54 | return email; 55 | } 56 | 57 | public void setEmail(String email) { 58 | this.email = email; 59 | } 60 | 61 | public String getHomeUrl() { 62 | return homeUrl; 63 | } 64 | 65 | public void setHomeUrl(String homeUrl) { 66 | this.homeUrl = homeUrl; 67 | } 68 | 69 | public String getScreenName() { 70 | return screenName; 71 | } 72 | 73 | public void setScreenName(String screenName) { 74 | this.screenName = screenName; 75 | } 76 | 77 | public Integer getCreated() { 78 | return created; 79 | } 80 | 81 | public void setCreated(Integer created) { 82 | this.created = created; 83 | } 84 | 85 | public Integer getActivated() { 86 | return activated; 87 | } 88 | 89 | public void setActivated(Integer activated) { 90 | this.activated = activated; 91 | } 92 | 93 | public Integer getLogged() { 94 | return logged; 95 | } 96 | 97 | public void setLogged(Integer logged) { 98 | this.logged = logged; 99 | } 100 | 101 | public String getGroupName() { 102 | return groupName; 103 | } 104 | 105 | public void setGroupName(String groupName) { 106 | this.groupName = groupName; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/SettingController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import com.wip.constant.LogActions; 4 | import com.wip.constant.WebConst; 5 | import com.wip.controller.BaseController; 6 | import com.wip.model.OptionsDomain; 7 | import com.wip.service.log.LogService; 8 | import com.wip.service.option.OptionService; 9 | import com.wip.utils.APIResponse; 10 | import com.wip.utils.GsonUtils; 11 | import io.swagger.annotations.Api; 12 | import io.swagger.annotations.ApiOperation; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Controller; 17 | import org.springframework.web.bind.annotation.GetMapping; 18 | import org.springframework.web.bind.annotation.PostMapping; 19 | import org.springframework.web.bind.annotation.RequestMapping; 20 | import org.springframework.web.bind.annotation.ResponseBody; 21 | 22 | import javax.servlet.http.HttpServletRequest; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | @Api("系统设置管理") 28 | @Controller 29 | @RequestMapping("admin/setting") 30 | public class SettingController extends BaseController { 31 | 32 | private static final Logger LOGGER = LoggerFactory.getLogger(SettingController.class); 33 | 34 | @Autowired 35 | private OptionService optionService; 36 | 37 | @Autowired 38 | private LogService logService; 39 | 40 | 41 | @ApiOperation("进入设置页") 42 | @GetMapping(value = "") 43 | public String index(HttpServletRequest request) { 44 | List optionsList = optionService.getOptions(); 45 | Map options = new HashMap<>(); 46 | optionsList.forEach((option) ->{ 47 | options.put(option.getName(),option.getValue()); 48 | }); 49 | request.setAttribute("options", options); 50 | return "admin/setting"; 51 | } 52 | 53 | @ApiOperation("保存系统设置") 54 | @PostMapping(value = "") 55 | @ResponseBody 56 | public APIResponse saveSetting(HttpServletRequest request) { 57 | 58 | try { 59 | Map parameterMap = request.getParameterMap(); 60 | Map querys = new HashMap<>(); 61 | parameterMap.forEach((key, value) -> { 62 | //System.out.println(key + "------" + join(value)); 63 | querys.put(key, join(value)); 64 | }); 65 | 66 | optionService.saveOptions(querys); 67 | WebConst.initConfig = querys; 68 | 69 | // 写入日志 70 | logService.addLog(LogActions.SYS_SETTING.getAction(),GsonUtils.toJsonString(querys),request.getRemoteAddr(),this.getUid(request)); 71 | return APIResponse.success(); 72 | 73 | } catch (Exception e) { 74 | String msg = "保存设置失败"; 75 | return APIResponse.fail(e.getMessage()); 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/resources/mapper/AttAchMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | t_attach 8 | 9 | 10 | 11 | 12 | aa.id, aa.fname, aa.ftype, aa.fkey, aa.authorId, aa.created, 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | u.username 23 | 24 | 25 | 26 | 27 | 28 | INSERT INTO 29 | 30 | 31 | fname, 32 | ftype, 33 | fkey, 34 | authorId, 35 | created 36 | 37 | 38 | #{fname, jdbcType=VARCHAR}, 39 | #{ftype, jdbcType=VARCHAR}, 40 | #{fkey, jdbcType=VARCHAR}, 41 | #{authorId, jdbcType=INTEGER}, 42 | UNIX_TIMESTAMP(NOW()) 43 | 44 | 45 | 46 | 47 | 62 | 63 | 64 | 70 | 71 | 72 | 87 | 88 | 89 | 90 | DELETE FROM 91 | 92 | WHERE 93 | id = #{id, jdbcType=INTEGER} 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/UUID.java: -------------------------------------------------------------------------------- 1 | package com.wip.utils; 2 | 3 | 4 | import java.util.Random; 5 | 6 | /** 7 | * 封装UUID 8 | */ 9 | public abstract class UUID { 10 | 11 | static Random r = new Random(); 12 | 13 | /** 14 | * 根据一个范围,生成一个随机的整数 15 | * @param min 最小值(包括) 16 | * @param max 最大值(包括) 17 | * @return 随机数 18 | */ 19 | public static int random(int min, int max) { 20 | return r.nextInt(max - min + 1) + min; 21 | } 22 | 23 | private static final char[] _UU64 = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".toCharArray(); 24 | private static final char[] _UU32 = "0123456789abcdefghijklmnopqrstuv".toCharArray(); 25 | 26 | /** 27 | * 64进制表示的紧凑格式的 UUID 28 | * @return 29 | */ 30 | public static String UU64() { 31 | return UU64(java.util.UUID.randomUUID()); 32 | } 33 | 34 | 35 | /** 36 | * 返回一个 UUID ,并用 64 进制转换成紧凑形式的字符串,内容为 [\\-0-9a-zA-Z_] 37 | *

38 | * 比如一个类似下面的 UUID: 39 | * 40 | *

 41 |      * a6c5c51c-689c-4525-9bcd-c14c1e107c80
 42 |      * 一共 128 位,分做L64 和 R64,分为为两个 64位数(两个 long)
 43 |      *    > L = uu.getLeastSignificantBits();
 44 |      *    > UUID = uu.getMostSignificantBits();
 45 |      * 而一个 64 进制数,是 6 位,因此我们取值的顺序是
 46 |      * 1. 从L64位取10次,每次取6位
 47 |      * 2. 从L64位取最后的4位 + R64位头2位拼上
 48 |      * 3. 从R64位取10次,每次取6位
 49 |      * 4. 剩下的两位最后取
 50 |      * 这样,就能用一个 22 长度的字符串表示一个 32 长度的UUID,压缩了 1/3
 51 |      * 
52 | * 53 | * @param uu 54 | * UUID 对象 55 | * @return 64进制表示的紧凑格式的 UUID 56 | */ 57 | public static String UU64(java.util.UUID uu) { 58 | int index = 0; 59 | char[] cs = new char[22]; 60 | long L = uu.getMostSignificantBits(); 61 | long R = uu.getLeastSignificantBits(); 62 | long mask = 63; 63 | // 从L64位取10次,每次取6位 64 | for (int off = 58; off >= 4; off -= 6) { 65 | long hex = (L & (mask << off)) >>> off; 66 | cs[index++] = _UU64[(int) hex]; 67 | } 68 | // 从L64位取最后的4位 + R64位头2位拼上 69 | int l = (int) (((L & 0xF) << 2) | ((R & (3 << 62)) >>> 62)); 70 | cs[index++] = _UU64[l]; 71 | // 从R64位取10次,每次取6位 72 | for (int off = 56; off >= 2; off -= 6) { 73 | long hex = (R & (mask << off)) >>> off; 74 | cs[index++] = _UU64[(int) hex]; 75 | } 76 | // 剩下的两位最后取 77 | cs[index++] = _UU64[(int) (R & 3)]; 78 | // 返回字符串 79 | return new String(cs); 80 | } 81 | public static String UU32(java.util.UUID uuid) { 82 | StringBuilder sb = new StringBuilder(); 83 | long m = uuid.getMostSignificantBits(); 84 | long l = uuid.getLeastSignificantBits(); 85 | for (int i = 0; i < 13; i++) { 86 | sb.append(_UU32[(int) (m >> ((13 - i - 1) * 5)) & 31]); 87 | } 88 | for (int i = 0; i < 13; i++) { 89 | sb.append(_UU32[(int) (m >> ((13 - i - 1) * 5)) & 31]); 90 | } 91 | return sb.toString(); 92 | } 93 | 94 | public static String UU32() { 95 | return UU32(java.util.UUID.randomUUID()); 96 | } 97 | 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/site/impl/SiteServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/8/2 8:48 5 | **/ 6 | package com.wip.service.site.impl; 7 | 8 | import com.github.pagehelper.PageHelper; 9 | import com.wip.constant.Types; 10 | import com.wip.dao.AttAchDao; 11 | import com.wip.dao.CommentDao; 12 | import com.wip.dao.ContentDao; 13 | import com.wip.dao.MetaDao; 14 | import com.wip.dto.StatisticsDto; 15 | import com.wip.dto.cond.CommentCond; 16 | import com.wip.dto.cond.ContentCond; 17 | import com.wip.model.CommentDomain; 18 | import com.wip.model.ContentDomain; 19 | import com.wip.service.site.SiteService; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.cache.annotation.Cacheable; 24 | import org.springframework.stereotype.Service; 25 | 26 | import java.util.List; 27 | 28 | @Service 29 | public class SiteServiceImpl implements SiteService { 30 | 31 | private static final Logger LOGGER = LoggerFactory.getLogger(SiteServiceImpl.class); 32 | 33 | @Autowired 34 | private CommentDao commentDao; 35 | 36 | @Autowired 37 | private ContentDao contentDao; 38 | 39 | @Autowired 40 | private MetaDao metaDao; 41 | 42 | @Autowired 43 | private AttAchDao attAchDao; 44 | 45 | 46 | 47 | @Override 48 | @Cacheable(value = "siteCache", key = "'comments_' + #p0") 49 | public List getComments(int limit) { 50 | LOGGER.debug("Enter recentComments method: limit={}", limit); 51 | if (limit < 0 || limit > 10) { 52 | limit = 10; 53 | } 54 | PageHelper.startPage(1,limit); 55 | List rs = commentDao.getCommentsByCond(new CommentCond()); 56 | LOGGER.debug("Exit recentComments method"); 57 | return rs; 58 | } 59 | 60 | @Override 61 | @Cacheable(value = "siteCache", key = "'newArticles_' + #p0") 62 | public List getNewArticles(int limit) { 63 | LOGGER.debug("Enter recentArticles method:limit={}",limit); 64 | if (limit < 0 || limit > 10) { 65 | limit = 10; 66 | } 67 | PageHelper.startPage(1,limit); 68 | List rs = contentDao.getArticleByCond(new ContentCond()); 69 | LOGGER.debug("Exit recentArticles method"); 70 | return rs; 71 | } 72 | 73 | @Override 74 | @Cacheable(value = "siteCache", key = "'statistics_'") 75 | public StatisticsDto getStatistics() { 76 | LOGGER.debug("Enter recentStatistics method"); 77 | 78 | // 文章总数 79 | Long articles = contentDao.getArticleCount(); 80 | 81 | // 评论总数 82 | Long comments = commentDao.getCommentCount(); 83 | 84 | // 链接数 85 | Long links = metaDao.getMetasCountByType(Types.LINK.getType()); 86 | 87 | // 获取附件数 88 | Long attAches = attAchDao.getAttAchCount(); 89 | 90 | StatisticsDto rs = new StatisticsDto(); 91 | rs.setArticles(articles); 92 | rs.setComments(comments); 93 | rs.setLinks(links); 94 | rs.setAttachs(attAches); 95 | LOGGER.debug("Exit recentStatistics method"); 96 | return rs; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/CategoryController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import com.wip.constant.Types; 4 | import com.wip.constant.WebConst; 5 | import com.wip.controller.BaseController; 6 | import com.wip.dto.MetaDto; 7 | import com.wip.exception.BusinessException; 8 | import com.wip.service.meta.MetaService; 9 | import com.wip.utils.APIResponse; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import io.swagger.annotations.ApiParam; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Controller; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | import java.util.List; 21 | 22 | @Api("分类管理") 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 | @Autowired 30 | private MetaService metaService; 31 | 32 | 33 | @ApiOperation("进入分类和标签页") 34 | @GetMapping(value = "") 35 | public String index(HttpServletRequest request) { 36 | List categories = metaService.getMetaList(Types.CATEGORY.getType(),null,WebConst.MAX_POSTS); 37 | List tags = metaService.getMetaList(Types.TAG.getType(), null, WebConst.MAX_POSTS); 38 | request.setAttribute("categories",categories); 39 | request.setAttribute("tags",tags); 40 | return "admin/category"; 41 | } 42 | 43 | @ApiOperation("保存分类") 44 | @PostMapping(value = "/save") 45 | @ResponseBody 46 | public APIResponse addCategory( 47 | @ApiParam(name = "cname", value = "分类名", required = true) 48 | @RequestParam(name = "cname", required = true) 49 | String cname, 50 | @ApiParam(name = "mid", value = "meta编号", required = false) 51 | @RequestParam(name = "mid", required = false) 52 | Integer mid 53 | ) { 54 | try { 55 | metaService.saveMeta(Types.CATEGORY.getType(),cname,mid); 56 | 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | String msg = "分类保存失败"; 60 | if (e instanceof BusinessException) { 61 | BusinessException ex = (BusinessException) e; 62 | msg = ex.getErrorCode(); 63 | } 64 | LOGGER.error(msg, e); 65 | return APIResponse.fail(msg); 66 | } 67 | return APIResponse.success(); 68 | } 69 | 70 | @ApiOperation("删除分类") 71 | @PostMapping(value = "/delete") 72 | @ResponseBody 73 | public APIResponse deleteCategory( 74 | @ApiParam(name = "mid", value = "meta编号", required = true) 75 | @RequestParam(name = "mid", required = true) 76 | Integer mid 77 | ) { 78 | try { 79 | metaService.deleteMetaById(mid); 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | LOGGER.error(e.getMessage()); 83 | return APIResponse.fail(e.getMessage()); 84 | } 85 | return APIResponse.success(); 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/MapCache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/23 10:37 5 | **/ 6 | package com.wip.utils; 7 | 8 | import javafx.collections.MapChangeListener; 9 | 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | /** 14 | * Map 缓存实现 15 | */ 16 | public class MapCache { 17 | /** 18 | * 默认存储1024个缓存 19 | */ 20 | private static final int DEFAULT_CACHES = 1024; 21 | 22 | private static final MapCache INS = new MapCache(); 23 | 24 | public static MapCache single() { 25 | return INS; 26 | } 27 | 28 | /** 29 | * 缓存容器 30 | */ 31 | private Map cachePool; 32 | 33 | public MapCache() { 34 | this(DEFAULT_CACHES); 35 | } 36 | 37 | public MapCache(int cacheCount) { 38 | cachePool = new ConcurrentHashMap<>(cacheCount); 39 | } 40 | 41 | 42 | /** 43 | * 设置一个缓存并带过期时间 44 | * @param key 缓存key 45 | * @param value 绑在value 46 | * @param expired 过期时间,单位为秒 47 | */ 48 | public void set(String key, Object value, long expired) { 49 | expired = expired > 0 ? System.currentTimeMillis() / 1000 + expired : expired; 50 | CacheObject cacheObject = new CacheObject(key, value, expired); 51 | cachePool.put(key,cacheObject); 52 | } 53 | 54 | /** 55 | * 设置一个hash缓存 56 | * @param key 57 | * @param field 58 | * @param value 59 | */ 60 | public void hset(String key, String field, Object value) { 61 | this.hset(key,field,value,-1); 62 | } 63 | 64 | 65 | /** 66 | * 设置一个hash缓存并带过期时间 67 | * @param key 缓存key 68 | * @param field 缓存field 69 | * @param value 缓存value 70 | * @param expired 过期时间,单位为秒 71 | */ 72 | public void hset(String key, String field, Object value, long expired) { 73 | key = key + ":" + field; 74 | expired = expired > 0 ? System.currentTimeMillis() / 1000 + expired : expired; 75 | CacheObject cacheObject = new CacheObject(key,value,expired); 76 | cachePool.put(key,cacheObject); 77 | } 78 | 79 | /** 80 | * 读取一个hash类型的缓存 81 | * @param key 缓存key 82 | * @param field 缓存field 83 | * @param 84 | * @return 85 | */ 86 | public T hget(String key, String field) { 87 | key = key + ":" + field; 88 | return this.get(key); 89 | } 90 | 91 | /** 92 | * 读取一个缓存 93 | * @param key 缓存key 94 | * @param 95 | * @return 96 | */ 97 | public T get(String key) { 98 | CacheObject cacheObject = cachePool.get(key); 99 | if (null != cacheObject) { 100 | long cur = System.currentTimeMillis() / 1000; 101 | if (cacheObject.getExpired() <= 0 || cacheObject.getExpired() > cur) { 102 | Object result = cacheObject.getValue(); 103 | return (T) result; 104 | } 105 | } 106 | return null; 107 | } 108 | 109 | 110 | /** 111 | * 缓存对象 112 | */ 113 | static class CacheObject { 114 | private String key; 115 | private Object value; 116 | private long expired; 117 | 118 | public CacheObject(String key, Object value, long expired) { 119 | this.key = key; 120 | this.value = value; 121 | this.expired = expired; 122 | } 123 | 124 | public String getKey() { 125 | return key; 126 | } 127 | 128 | public Object getValue() { 129 | return value; 130 | } 131 | 132 | public long getExpired() { 133 | return expired; 134 | } 135 | 136 | } 137 | 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/CommentDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/31 15:27 5 | **/ 6 | package com.wip.model; 7 | 8 | /** 9 | * 评论表 10 | */ 11 | public class CommentDomain { 12 | /** 13 | * comment表主键 14 | */ 15 | private Integer coid; 16 | /** 17 | * contents表主键,关联字段 18 | */ 19 | private Integer cid; 20 | /** 21 | * 评论生成时的GMT unix时间戳 22 | */ 23 | private Integer created; 24 | /** 25 | * 评论作者 26 | */ 27 | private String author; 28 | /** 29 | * 评论所属用户id 30 | */ 31 | private String authorId; 32 | /** 33 | * 评论所属内容作者id 34 | */ 35 | private Integer ownerId; 36 | /** 37 | * 评论者邮件 38 | */ 39 | private String mail; 40 | /** 41 | * 评论者网址 42 | */ 43 | private String url; 44 | /** 45 | * 评论者ip地址 46 | * 47 | */ 48 | private String ip; 49 | /** 50 | * 评论者客户端 51 | */ 52 | private String agent; 53 | /** 54 | * 评论类型 55 | */ 56 | private String type; 57 | /** 58 | * 评论状态 59 | */ 60 | private String status; 61 | /** 62 | * 父级评论 63 | */ 64 | private Integer parent; 65 | /** 66 | * 评论内容 67 | */ 68 | private String content; 69 | 70 | public Integer getCoid() { 71 | return coid; 72 | } 73 | 74 | public void setCoid(Integer coid) { 75 | this.coid = coid; 76 | } 77 | 78 | public Integer getCid() { 79 | return cid; 80 | } 81 | 82 | public void setCid(Integer cid) { 83 | this.cid = cid; 84 | } 85 | 86 | public Integer getCreated() { 87 | return created; 88 | } 89 | 90 | public void setCreated(Integer created) { 91 | this.created = created; 92 | } 93 | 94 | public String getAuthor() { 95 | return author; 96 | } 97 | 98 | public void setAuthor(String author) { 99 | this.author = author; 100 | } 101 | 102 | public String getAuthorId() { 103 | return authorId; 104 | } 105 | 106 | public void setAuthorId(String authorId) { 107 | this.authorId = authorId; 108 | } 109 | 110 | public Integer getOwnerId() { 111 | return ownerId; 112 | } 113 | 114 | public void setOwnerId(Integer ownerId) { 115 | this.ownerId = ownerId; 116 | } 117 | 118 | public String getEmail() { 119 | return mail; 120 | } 121 | 122 | public void setEmail(String email) { 123 | this.mail = email; 124 | } 125 | 126 | public String getUrl() { 127 | return url; 128 | } 129 | 130 | public void setUrl(String url) { 131 | this.url = url; 132 | } 133 | 134 | public String getAgent() { 135 | return agent; 136 | } 137 | 138 | public void setAgent(String agent) { 139 | this.agent = agent; 140 | } 141 | 142 | public String getType() { 143 | return type; 144 | } 145 | 146 | public void setType(String type) { 147 | this.type = type; 148 | } 149 | 150 | public String getStatus() { 151 | return status; 152 | } 153 | 154 | public void setStatus(String status) { 155 | this.status = status; 156 | } 157 | 158 | public Integer getParent() { 159 | return parent; 160 | } 161 | 162 | public void setParent(Integer parent) { 163 | this.parent = parent; 164 | } 165 | 166 | public String getContent() { 167 | return content; 168 | } 169 | 170 | public void setContent(String content) { 171 | this.content = content; 172 | } 173 | 174 | public String getIp() { 175 | return ip; 176 | } 177 | 178 | public void setIp(String ip) { 179 | this.ip = ip; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/LinksController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import com.wip.constant.ErrorConstant; 4 | import com.wip.constant.Types; 5 | import com.wip.controller.BaseController; 6 | import com.wip.dto.cond.MetaCond; 7 | import com.wip.exception.BusinessException; 8 | import com.wip.model.MetaDomain; 9 | import com.wip.service.meta.MetaService; 10 | import com.wip.utils.APIResponse; 11 | import io.swagger.annotations.Api; 12 | import io.swagger.annotations.ApiOperation; 13 | import io.swagger.annotations.ApiParam; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Controller; 18 | import org.springframework.web.bind.annotation.*; 19 | 20 | import javax.servlet.http.HttpServletRequest; 21 | import java.util.List; 22 | 23 | @Api("友情链接管理") 24 | @Controller 25 | @RequestMapping("/admin/links") 26 | public class LinksController extends BaseController { 27 | 28 | private static final Logger LOGGER = LoggerFactory.getLogger(LinksController.class); 29 | 30 | @Autowired 31 | private MetaService metaService; 32 | 33 | 34 | @ApiOperation("友链页面") 35 | @GetMapping(value = "") 36 | public String index(HttpServletRequest request) { 37 | MetaCond metaCond = new MetaCond(); 38 | metaCond.setType(Types.LINK.getType()); 39 | List metas = metaService.getMetas(metaCond); 40 | request.setAttribute("links", metas); 41 | return "admin/links"; 42 | } 43 | 44 | @ApiOperation("新增友情链接") 45 | @PostMapping(value = "/save") 46 | @ResponseBody 47 | public APIResponse addLink( 48 | @ApiParam(name = "title", value = "标签", required = true) 49 | @RequestParam(name = "title", required = true) 50 | String title, 51 | @ApiParam(name = "url", value = "链接", required = true) 52 | @RequestParam(name = "url", required = true) 53 | String url, 54 | @ApiParam(name = "logo", value = "logo", required = false) 55 | @RequestParam(name = "logo", required = false) 56 | String logo, 57 | @ApiParam(name = "mid", value = "meta编号", required = false) 58 | @RequestParam(name = "mid", required = false) 59 | Integer mid, 60 | @ApiParam(name = "sort", value = "sort", required = false) 61 | @RequestParam(name = "sort", required = false, defaultValue = "0") 62 | int sort 63 | ) { 64 | try { 65 | MetaDomain meta = new MetaDomain(); 66 | meta.setName(title); 67 | meta.setSlug(url); 68 | meta.setDescription(logo); 69 | meta.setSort(sort); 70 | meta.setType(Types.LINK.getType()); 71 | if (null != mid) { 72 | meta.setMid(mid); 73 | metaService.updateMeta(meta); 74 | } else { 75 | metaService.addMea(meta); 76 | } 77 | 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | throw BusinessException.withErrorCode(ErrorConstant.Meta.ADD_META_FAIL); 81 | } 82 | 83 | return APIResponse.success(); 84 | } 85 | 86 | @ApiOperation("删除友情链接") 87 | @PostMapping(value = "/delete") 88 | @ResponseBody 89 | public APIResponse deleteLink( 90 | @ApiParam(name = "mid", value = "meta主键", required = true) 91 | @RequestParam(name = "mid", required = true) 92 | int mid 93 | ) { 94 | try { 95 | metaService.deleteMetaById(mid); 96 | } catch (Exception e) { 97 | e.printStackTrace(); 98 | throw BusinessException.withErrorCode(ErrorConstant.Meta.DELETE_META_FAIL); 99 | } 100 | 101 | return APIResponse.success(); 102 | } 103 | 104 | 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/CommentController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.wip.controller.BaseController; 5 | import com.wip.dto.cond.CommentCond; 6 | import com.wip.model.CommentDomain; 7 | import com.wip.model.UserDomain; 8 | import com.wip.service.comment.CommentService; 9 | import com.wip.utils.APIResponse; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import io.swagger.annotations.ApiParam; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Controller; 17 | import org.springframework.web.bind.annotation.*; 18 | 19 | import javax.servlet.http.HttpServlet; 20 | import javax.servlet.http.HttpServletRequest; 21 | 22 | @Api("评论相关接口") 23 | @Controller 24 | @RequestMapping("/admin/comments") 25 | public class CommentController extends BaseController { 26 | 27 | private static final Logger LOGGER = LoggerFactory.getLogger(CommentController.class); 28 | 29 | @Autowired 30 | private CommentService commentService; 31 | 32 | @ApiOperation("进入评论列表页") 33 | @GetMapping(value = "") 34 | public String index( 35 | @ApiParam(name = "page", value = "页数", required = false) 36 | @RequestParam(name = "page", required = false, defaultValue = "1") 37 | int page, 38 | @ApiParam(name = "limit", value = "每页条数", required = false) 39 | @RequestParam(name = "limit", required = false, defaultValue = "15") 40 | int limit, 41 | HttpServletRequest request 42 | 43 | ) { 44 | UserDomain user = this.user(request); 45 | PageInfo comments = commentService.getCommentsByCond(new CommentCond(), page, limit); 46 | request.setAttribute("comments", comments); 47 | return "admin/comment_list"; 48 | } 49 | 50 | @ApiOperation("审核评论") 51 | @PostMapping(value = "/status") 52 | @ResponseBody 53 | public APIResponse changeStatus( 54 | HttpServletRequest request, 55 | @ApiParam(name = "coid", value = "评论主键", required = true) 56 | @RequestParam(name = "coid", required = true) 57 | Integer coid, 58 | @ApiParam(name = "status", value = "状态", required = true) 59 | @RequestParam(name = "status", required = true) 60 | String status 61 | ) { 62 | try { 63 | CommentDomain comment = commentService.getCommentById(coid); 64 | if (null != comment) { 65 | commentService.updateCommentStatus(coid,status); 66 | } else { 67 | return APIResponse.fail("通过失败"); 68 | } 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | LOGGER.error(e.getMessage()); 72 | return APIResponse.fail(e.getMessage()); 73 | } 74 | return APIResponse.success(); 75 | } 76 | @ApiOperation("删除评论") 77 | @PostMapping(value = "/delete") 78 | @ResponseBody 79 | public APIResponse deleteStatus( 80 | HttpServletRequest request, 81 | @ApiParam(name = "coid", value = "评论主键", required = true) 82 | @RequestParam(name = "coid", required = true) 83 | Integer coid 84 | ) { 85 | try { 86 | CommentDomain comment = commentService.getCommentById(coid); 87 | if (null != comment) { 88 | commentService.deleteComment(coid); 89 | } else { 90 | return APIResponse.fail("通过失败"); 91 | } 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | LOGGER.error(e.getMessage()); 95 | return APIResponse.fail(e.getMessage()); 96 | } 97 | return APIResponse.success(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/resources/mapper/CommentMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | t_comments 8 | 9 | 10 | 11 | cm.coid, cm.cid, cm.created, cm.author, cm.authorId, cm.ownerId, cm.mail, 12 | cm.url, cm.ip, cm.agent, cm.type, cm.status, cm.parent, cm.content 13 | 14 | 15 | 16 | 17 | INSERT INTO 18 | 19 | 20 | cid, created, author,authorId,ownerId,mail, 21 | url, ip, agent, type, status, parent, content 22 | 23 | 24 | #{cid, jdbcType=INTEGER}, 25 | #{created, jdbcType=INTEGER}, 26 | #{author, jdbcType=VARCHAR}, 27 | #{authorId, jdbcType=INTEGER}, 28 | #{ownerId, jdbcType=INTEGER}, 29 | #{email, jdbcType=VARCHAR}, 30 | #{url, jdbcType=VARCHAR}, 31 | #{ip, jdbcType=VARCHAR}, 32 | #{agent, jdbcType=VARCHAR}, 33 | #{type, jdbcType=VARCHAR}, 34 | #{status, jdbcType=VARCHAR}, 35 | #{parent, jdbcType=INTEGER}, 36 | #{content, jdbcType=LONGVARCHAR} 37 | 38 | 39 | 40 | 52 | 53 | 54 | 55 | DELETE FROM 56 | 57 | WHERE 58 | coid = #{coid, jdbcType=INTEGER} 59 | 60 | 61 | 62 | 68 | 69 | 70 | 91 | 92 | 93 | 101 | 102 | 103 | 104 | UPDATE 105 | 106 | SET 107 | status = #{status, jdbcType=VARCHAR} 108 | WHERE 109 | coid = #{coid, jdbcType=INTEGER} 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/IpInfoUtil.java: -------------------------------------------------------------------------------- 1 | package com.wip.utils; 2 | 3 | import cn.hutool.http.HttpUtil; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonParser; 6 | import io.swagger.annotations.ApiModelProperty; 7 | import io.swagger.annotations.ApiOperation; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import java.net.InetAddress; 13 | import java.net.UnknownHostException; 14 | import java.util.Objects; 15 | 16 | /** 17 | * IP地址工具类 18 | * @author 郑为中 19 | */ 20 | @Slf4j 21 | @Component 22 | public class IpInfoUtil { 23 | 24 | @ApiModelProperty(value = "腾讯地图的KEY值") 25 | private String key = "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"; 26 | 27 | private static final String IP_HEADER_PRE_ONE = "x-forwarded-for"; 28 | 29 | private static final String IP_HEADER_PRE_TWO = "Proxy-Client-IP"; 30 | 31 | private static final String IP_HEADER_PRE_THREE = "WL-Proxy-Client-IP"; 32 | 33 | private static final String IP_HEADER_NONE = "unknown"; 34 | 35 | private static final String IP_HEADER_LOCAL_HOST = "127.0.0.1"; 36 | 37 | private static final String IP_HEADER_LOCAL_LONG_HOST = "0:0:0:0:0:0:0:1"; 38 | 39 | private static final String TXDT_URL_PRE = "https://apis.map.qq.com/ws/location/v1/ip?key="; 40 | 41 | @ApiOperation(value = "查询IP地址的区县") 42 | public String getIpCity(HttpServletRequest request){ 43 | String url = TXDT_URL_PRE + key + "&ip=" + getIpAddr(request); 44 | String resultStr = "本地测试"; 45 | try { 46 | JsonParser jsonParser = new JsonParser(); 47 | JsonObject objectResult = jsonParser.parse(HttpUtil.get(url, 3000)).getAsJsonObject(); 48 | if(Objects.equals(objectResult.get("status").getAsString(),"0")) { 49 | JsonObject adInfo = objectResult.get("result").getAsJsonObject().get("ad_info").getAsJsonObject(); 50 | String nationStr = adInfo.get("nation").getAsString(); 51 | String provinceStr = adInfo.get("province").getAsString(); 52 | String cityStr = adInfo.get("city").getAsString(); 53 | String districtStr = adInfo.get("district").getAsString(); 54 | if(!ZwzNullUtils.isNull(nationStr) && ZwzNullUtils.isNull(provinceStr)){ 55 | resultStr = nationStr; 56 | } else { 57 | resultStr = provinceStr; 58 | if(!ZwzNullUtils.isNull(cityStr)){ 59 | resultStr += "-" + cityStr; 60 | } 61 | if(!ZwzNullUtils.isNull(districtStr)){ 62 | resultStr += "-" + districtStr; 63 | } 64 | } 65 | } 66 | } catch (Exception e) { 67 | log.warn("区县查询失败"); 68 | } 69 | return resultStr; 70 | } 71 | 72 | @ApiOperation(value = "查询请求的IP地址") 73 | public String getIpAddr(HttpServletRequest request) { 74 | String ipAddress = request.getHeader(IP_HEADER_PRE_ONE); 75 | if (ipAddress == null || ipAddress.length() < 1 || IP_HEADER_NONE.equalsIgnoreCase(ipAddress)) { 76 | ipAddress = request.getHeader(IP_HEADER_PRE_TWO); 77 | } 78 | if (ipAddress == null || ipAddress.length() < 1 || IP_HEADER_NONE.equalsIgnoreCase(ipAddress)) { 79 | ipAddress = request.getHeader(IP_HEADER_PRE_THREE); 80 | } 81 | if (ipAddress == null || ipAddress.length() < 1 || IP_HEADER_NONE.equalsIgnoreCase(ipAddress)) { 82 | ipAddress = request.getRemoteAddr(); 83 | if (Objects.equals(IP_HEADER_LOCAL_HOST,ipAddress)) { 84 | InetAddress inetAddress = null; 85 | try { 86 | inetAddress = InetAddress.getLocalHost(); 87 | } catch (UnknownHostException exception) { 88 | exception.printStackTrace(); 89 | } 90 | ipAddress = inetAddress.getHostAddress(); 91 | } 92 | } 93 | if (ipAddress != null && ipAddress.length() > 15) { 94 | if (ipAddress.indexOf(",") > 0) { 95 | ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); 96 | } 97 | } 98 | if(Objects.equals(IP_HEADER_LOCAL_LONG_HOST,ipAddress)){ 99 | ipAddress = IP_HEADER_LOCAL_HOST; 100 | } 101 | return ipAddress; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import com.wip.constant.LogActions; 4 | import com.wip.constant.WebConst; 5 | import com.wip.controller.BaseController; 6 | import com.wip.exception.BusinessException; 7 | import com.wip.model.UserDomain; 8 | import com.wip.service.log.LogService; 9 | import com.wip.service.user.UserService; 10 | import com.wip.utils.APIResponse; 11 | import com.wip.utils.GsonUtils; 12 | import com.wip.utils.TaleUtils; 13 | import io.swagger.annotations.Api; 14 | import io.swagger.annotations.ApiOperation; 15 | import io.swagger.annotations.ApiParam; 16 | import org.apache.commons.lang3.StringUtils; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import org.springframework.beans.factory.annotation.Autowired; 20 | import org.springframework.stereotype.Controller; 21 | import org.springframework.web.bind.annotation.*; 22 | 23 | import javax.servlet.http.Cookie; 24 | import javax.servlet.http.HttpServletRequest; 25 | import javax.servlet.http.HttpServletResponse; 26 | import javax.servlet.http.HttpSession; 27 | import java.io.IOException; 28 | 29 | @Api("登录相关接口") 30 | @Controller 31 | @RequestMapping("/admin") 32 | public class AuthController extends BaseController { 33 | 34 | private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class); 35 | 36 | @Autowired 37 | private UserService userService; 38 | 39 | @Autowired 40 | private LogService logService; 41 | 42 | 43 | @ApiOperation("跳转登录页") 44 | @GetMapping(value = "/login") 45 | public String login() { 46 | return "admin/login"; 47 | } 48 | 49 | 50 | @ApiOperation("登录") 51 | @PostMapping(value = "/login") 52 | @ResponseBody 53 | public APIResponse toLogin( 54 | HttpServletRequest request, 55 | HttpServletResponse response, 56 | @ApiParam(name = "username", value = "用户名", required = true) 57 | @RequestParam(name = "username", required = true) 58 | String username, 59 | @ApiParam(name = "password", value = "用户名", required = true) 60 | @RequestParam(name = "password", required = true) 61 | String password, 62 | @ApiParam(name = "remember_me", value = "记住我", required = false) 63 | @RequestParam(name = "remember_me", required = false) 64 | String remember_me 65 | ) { 66 | Integer error_count = cache.get("login_error_count"); 67 | try { 68 | // 调用Service登录方法 69 | UserDomain userInfo = userService.login(username, password); 70 | // 设置用户信息session 71 | request.getSession().setAttribute(WebConst.LOGIN_SESSION_KEY, userInfo); 72 | // 判断是否勾选记住我 73 | if (StringUtils.isNotBlank(remember_me)) { 74 | TaleUtils.setCookie(response, userInfo.getUid()); 75 | } 76 | // 写入日志 77 | logService.addLog(LogActions.LOGIN.getAction(), userInfo.getUsername()+"用户", request.getRemoteAddr(), userInfo.getUid()); 78 | } catch (Exception e) { 79 | LOGGER.error(e.getMessage()); 80 | error_count = null == error_count ? 1 : error_count + 1; 81 | if (error_count > 3) { 82 | return APIResponse.fail("您输入密码已经错误超过3次,请10分钟后尝试"); 83 | } 84 | System.out.println(error_count); 85 | // 设置缓存为10分钟 86 | cache.set("login_error_count", error_count, 10 * 60); 87 | String msg = "登录失败"; 88 | if (e instanceof BusinessException) { 89 | msg = e.getMessage(); 90 | } else { 91 | LOGGER.error(msg,e); 92 | } 93 | return APIResponse.fail(msg); 94 | } 95 | // 返回登录成功信息 96 | return APIResponse.success(); 97 | } 98 | 99 | @RequestMapping(value = "/logout") 100 | public void logout(HttpSession session, HttpServletRequest request, HttpServletResponse response) { 101 | // 移除session 102 | session.removeAttribute(WebConst.LOGIN_SESSION_KEY); 103 | // 设置cookie值和时间为空 104 | Cookie cookie = new Cookie(WebConst.USER_IN_COOKIE, ""); 105 | cookie.setValue(null); 106 | cookie.setMaxAge(0); 107 | cookie.setPath("/"); 108 | response.addCookie(cookie); 109 | try { 110 | // 跳转到登录页面 111 | response.sendRedirect("/admin/login"); 112 | } catch (IOException e) { 113 | e.printStackTrace(); 114 | LOGGER.error("注销失败",e); 115 | } 116 | } 117 | 118 | 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/wip/model/ContentDomain.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/25 16:30 5 | **/ 6 | package com.wip.model; 7 | 8 | /** 9 | * 文章表 10 | */ 11 | public class ContentDomain { 12 | /** 13 | * 文章的主键编号 14 | */ 15 | private Integer cid; 16 | /** 17 | * 内容标题 18 | */ 19 | private String title; 20 | /** 21 | * 标题图片 22 | */ 23 | private String titlePic; 24 | /** 25 | * 内容缩略名 26 | */ 27 | private String slug; 28 | /** 29 | * 内容生成时的GMT unix时间戳 30 | */ 31 | private Integer created; 32 | /** 33 | * 内容更改时的GMT unix时间戳 34 | */ 35 | private Integer modified; 36 | /** 37 | * 内容文字 38 | */ 39 | private String content; 40 | /** 41 | * 内容所属用户id 42 | */ 43 | private Integer authorId; 44 | /** 45 | * 内容类别 46 | */ 47 | private String type; 48 | /** 49 | * 内容状态 50 | */ 51 | private String status; 52 | /** 53 | * 标签列表 54 | */ 55 | private String tags; 56 | /** 57 | * 分类列表 58 | */ 59 | private String categories; 60 | /** 61 | * 点击次数 62 | */ 63 | private Integer hits; 64 | /** 65 | * 内容所属评论数 66 | */ 67 | private Integer commentsNum; 68 | /** 69 | * 是否允许评论 70 | */ 71 | private Integer allowComment; 72 | /** 73 | * 是否允许ping 74 | */ 75 | private Integer allowPing; 76 | /** 77 | * 允许出现在聚合中 78 | */ 79 | private Integer allowFeed; 80 | 81 | public Integer getCid() { 82 | return cid; 83 | } 84 | 85 | public void setCid(Integer cid) { 86 | this.cid = cid; 87 | } 88 | 89 | public String getTitle() { 90 | return title; 91 | } 92 | 93 | public void setTitle(String title) { 94 | this.title = title; 95 | } 96 | 97 | public String getTitlePic() { 98 | return titlePic; 99 | } 100 | 101 | public void setTitlePic(String titlePic) { 102 | this.titlePic = titlePic; 103 | } 104 | 105 | public String getSlug() { 106 | return slug; 107 | } 108 | 109 | public void setSlug(String slug) { 110 | this.slug = slug; 111 | } 112 | 113 | public Integer getCreated() { 114 | return created; 115 | } 116 | 117 | public void setCreated(Integer created) { 118 | this.created = created; 119 | } 120 | 121 | public Integer getModified() { 122 | return modified; 123 | } 124 | 125 | public void setModified(Integer modified) { 126 | this.modified = modified; 127 | } 128 | 129 | public String getContent() { 130 | return content; 131 | } 132 | 133 | public void setContent(String content) { 134 | this.content = content; 135 | } 136 | 137 | public Integer getAuthorId() { 138 | return authorId; 139 | } 140 | 141 | public void setAuthorId(Integer authorId) { 142 | this.authorId = authorId; 143 | } 144 | 145 | public String getType() { 146 | return type; 147 | } 148 | 149 | public void setType(String type) { 150 | this.type = type; 151 | } 152 | 153 | public String getStatus() { 154 | return status; 155 | } 156 | 157 | public void setStatus(String status) { 158 | this.status = status; 159 | } 160 | 161 | public String getTags() { 162 | return tags; 163 | } 164 | 165 | public void setTags(String tags) { 166 | this.tags = tags; 167 | } 168 | 169 | public String getCategories() { 170 | return categories; 171 | } 172 | 173 | public void setCategories(String categories) { 174 | this.categories = categories; 175 | } 176 | 177 | public Integer getHits() { 178 | return hits; 179 | } 180 | 181 | public void setHits(Integer hits) { 182 | this.hits = hits; 183 | } 184 | 185 | public Integer getCommentsNum() { 186 | return commentsNum; 187 | } 188 | 189 | public void setCommentsNum(Integer commentsNum) { 190 | this.commentsNum = commentsNum; 191 | } 192 | 193 | public Integer getAllowComment() { 194 | return allowComment; 195 | } 196 | 197 | public void setAllowComment(Integer allowComment) { 198 | this.allowComment = allowComment; 199 | } 200 | 201 | public Integer getAllowPing() { 202 | return allowPing; 203 | } 204 | 205 | public void setAllowPing(Integer allowPing) { 206 | this.allowPing = allowPing; 207 | } 208 | 209 | public Integer getAllowFeed() { 210 | return allowFeed; 211 | } 212 | 213 | public void setAllowFeed(Integer allowFeed) { 214 | this.allowFeed = allowFeed; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/comment/impl/CommentServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/31 15:40 5 | **/ 6 | package com.wip.service.comment.impl; 7 | 8 | import com.github.pagehelper.PageHelper; 9 | import com.github.pagehelper.PageInfo; 10 | import com.wip.constant.ErrorConstant; 11 | import com.wip.dao.CommentDao; 12 | import com.wip.dto.cond.CommentCond; 13 | import com.wip.exception.BusinessException; 14 | import com.wip.model.CommentDomain; 15 | import com.wip.model.ContentDomain; 16 | import com.wip.service.article.ContentService; 17 | import com.wip.service.comment.CommentService; 18 | import com.wip.utils.DateKit; 19 | import com.wip.utils.TaleUtils; 20 | import org.apache.commons.lang3.StringUtils; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.cache.annotation.CacheEvict; 23 | import org.springframework.cache.annotation.Cacheable; 24 | import org.springframework.stereotype.Service; 25 | import org.springframework.transaction.annotation.Transactional; 26 | 27 | import java.util.List; 28 | import java.util.Map; 29 | import java.util.concurrent.ConcurrentHashMap; 30 | 31 | @Service 32 | public class CommentServiceImpl implements CommentService { 33 | 34 | @Autowired 35 | private CommentDao commentDao; 36 | 37 | @Autowired 38 | private ContentService contentService; 39 | 40 | private static final Map STATUS_MAP = new ConcurrentHashMap<>(); 41 | 42 | /** 43 | * 评论状态:正常 44 | */ 45 | private static final String STATUS_NORMAL = "approved"; 46 | /** 47 | * 评论状态:不不显示 48 | */ 49 | private static final String STATUS_BLANK = "not_audit"; 50 | 51 | static { 52 | STATUS_MAP.put("approved",STATUS_NORMAL); 53 | STATUS_MAP.put("not_audit",STATUS_BLANK); 54 | } 55 | 56 | 57 | @Override 58 | @Transactional 59 | @CacheEvict(value = "commentCache", allEntries = true) 60 | public void addComment(CommentDomain comments) { 61 | String msg = null; 62 | 63 | if (null == comments) { 64 | msg = "评论对象为空"; 65 | } 66 | 67 | if (StringUtils.isBlank(comments.getAuthor())) { 68 | comments.setAuthor("热心网友"); 69 | } 70 | if (StringUtils.isNotBlank(comments.getEmail()) && !TaleUtils.isEmail(comments.getEmail())) { 71 | msg = "请输入正确的邮箱格式"; 72 | } 73 | if (StringUtils.isBlank(comments.getContent())) { 74 | msg = "评论内容不能为空"; 75 | } 76 | /*if (comments.getContent().length() < 5 || comments.getContent().length() > 2000) { 77 | msg = "评论字数在5-2000个字符"; 78 | }*/ 79 | if (null == comments.getCid()) { 80 | msg = "评论文章不能为空"; 81 | } 82 | if (msg != null) 83 | throw BusinessException.withErrorCode(msg); 84 | 85 | ContentDomain article = contentService.getArticleById(comments.getCid()); 86 | if (null == article) { 87 | throw BusinessException.withErrorCode("该文章不存在"); 88 | } 89 | 90 | comments.setOwnerId(article.getAuthorId()); 91 | comments.setStatus(STATUS_MAP.get(STATUS_BLANK)); 92 | comments.setCreated(DateKit.getCurrentUnixTime()); 93 | commentDao.addComment(comments); 94 | 95 | ContentDomain temp = new ContentDomain(); 96 | temp.setCid(article.getCid()); 97 | Integer count = article.getCommentsNum(); 98 | if (null == count) { 99 | count = 0; 100 | } 101 | temp.setCommentsNum(count + 1); 102 | contentService.updateContentByCid(temp); 103 | 104 | } 105 | 106 | @Override 107 | @Cacheable(value = "commentCache", key = "'commentsByCId_' + #p0") 108 | public List getCommentsByCId(Integer cid) { 109 | if (null == cid) 110 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 111 | return commentDao.getCommentByCId(cid); 112 | } 113 | 114 | @Override 115 | @Cacheable(value = "commentCache", key = "'commentsByCond_'+ #p1") 116 | public PageInfo getCommentsByCond(CommentCond commentCond, int pageNum, int pageSize) { 117 | if (null == commentCond) 118 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 119 | PageHelper.startPage(pageNum,pageSize); 120 | List comments = commentDao.getCommentsByCond(commentCond); 121 | PageInfo pageInfo = new PageInfo<>(comments); 122 | return pageInfo; 123 | } 124 | 125 | @Override 126 | @Cacheable(value = "commentCache",key = "'commentById_' + #p0") 127 | public CommentDomain getCommentById(Integer coid) { 128 | if (null == coid) 129 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 130 | return commentDao.getCommentById(coid); 131 | } 132 | 133 | @Override 134 | @CacheEvict(value = "commentCache", allEntries = true) 135 | public void updateCommentStatus(Integer coid, String status) { 136 | if (null == coid) 137 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 138 | commentDao.updateCommentStatus(coid, status); 139 | } 140 | 141 | @Override 142 | public void deleteComment(Integer coid) { 143 | if (null == coid) 144 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 145 | commentDao.deleteComment(coid); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/resources/mapper/MetaMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | t_metas 8 | 9 | 10 | 11 | m.mid, m.name, m.slug, m.type, m.contentType, m.description, m.sort, m.parent 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | UPDATE 22 | 23 | 24 | 25 | name = #{name, jdbcType=VARCHAR}, 26 | 27 | 28 | slug = #{slug, jdbcType=VARCHAR}, 29 | 30 | 31 | type = #{type, jdbcType=VARCHAR}, 32 | 33 | 34 | description = #{description, jdbcType=VARCHAR}, 35 | 36 | 37 | sort = #{sort, jdbcType=INTEGER}, 38 | 39 | 40 | parent = #{parent, jdbcType=INTEGER}, 41 | 42 | 43 | WHERE mid = #{mid, jdbcType=INTEGER} 44 | 45 | 46 | 47 | 55 | 56 | 57 | 58 | INSERT INTO 59 | 60 | 61 | name, slug, type, description, sort, parent 62 | 63 | VALUES 64 | 65 | #{name, jdbcType=VARCHAR}, 66 | #{slug, jdbcType=VARCHAR}, 67 | #{type, jdbcType=VARCHAR}, 68 | #{description, jdbcType=VARCHAR}, 69 | #{sort, jdbcType=INTEGER}, 70 | #{parent, jdbcType=INTEGER} 71 | 72 | 73 | 74 | 75 | 90 | 91 | 92 | 93 | DELETE FROM 94 | 95 | WHERE 96 | mid = #{mid, jdbcType=INTEGER} 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 131 | 132 | 133 | 141 | 142 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/Commons.java: -------------------------------------------------------------------------------- 1 | package com.wip.utils; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.vdurmont.emoji.EmojiParser; 5 | import com.wip.constant.WebConst; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Random; 12 | 13 | 14 | /** 15 | * 公共函数 16 | */ 17 | @Component 18 | public class Commons { 19 | 20 | 21 | /** 22 | * 获取随机数数 23 | * @param max 24 | * @param str 25 | * @return 26 | */ 27 | public static String random(int max, String str) { 28 | return UUID.random(1,max) + str; 29 | } 30 | 31 | public static String random(Long seed, int max, String str) { 32 | if (seed == null) { 33 | return random(max, str); 34 | } 35 | Random random = new Random(seed); 36 | return random.nextInt(max) +str; 37 | } 38 | 39 | /** 40 | * 生成指定范围的随机整数 41 | * @param member 42 | * @return 43 | */ 44 | public static String randomInt(int member,String suf) { 45 | Random random = new Random(); 46 | return random.nextInt(member) + member + suf; 47 | } 48 | 49 | /** 50 | * 返回gitHub头像地址 51 | * @param email 邮箱 52 | * @return 头像链接地址 53 | */ 54 | public static String gravatar(String email) { 55 | String avatarUrl = "https://github.com/ynwynw/"; 56 | if (StringUtils.isBlank(email)) { 57 | email = "931708230@qq.com"; 58 | } 59 | String hash = TaleUtils.MD5encode(email.trim().toLowerCase()); 60 | return avatarUrl + hash + ".png"; 61 | } 62 | 63 | /** 64 | * 格式化unix时间戳为日期 65 | * @param unixTime 66 | * @param patten 67 | * @return 68 | */ 69 | public static String fmtdate(Integer unixTime, String patten) { 70 | if (null != unixTime && StringUtils.isNotBlank(patten)) { 71 | return DateKit.formatDateByUnixTime(unixTime,patten); 72 | } 73 | return ""; 74 | } 75 | 76 | /** 77 | * 返回blog文章地址 78 | * @param cid 79 | * @return 80 | */ 81 | public static String blogPermalink(Integer cid) { 82 | return site_url("/blog/article/" + cid.toString()); 83 | } 84 | 85 | /** 86 | * 网站链接 87 | * @return 88 | */ 89 | public static String site_url() { 90 | return site_url(""); 91 | } 92 | 93 | /** 94 | * 返回网站链接下的全址 95 | * @param sub 后面追加的地址 96 | * @return 97 | */ 98 | public static String site_url(String sub) { 99 | return site_option("site_url") + sub; 100 | } 101 | 102 | /** 103 | * 获取网站备案信息 104 | * @return 105 | */ 106 | public static String site_record() { 107 | return site_option("site_record"); 108 | } 109 | 110 | /** 111 | * 网站配置项 112 | * @param key 113 | * @return 114 | */ 115 | public static String site_option(String key) { 116 | return site_option(key, ""); 117 | } 118 | 119 | /** 120 | * 网站配置项 121 | * @param key 键名 122 | * @param defaultValue 默认值 123 | * @return 124 | */ 125 | public static String site_option(String key, String defaultValue) { 126 | if (StringUtils.isBlank(key)) { 127 | return ""; 128 | } 129 | String str = WebConst.initConfig.get(key); 130 | if (StringUtils.isNotBlank(str)) { 131 | return str; 132 | } else { 133 | return defaultValue; 134 | } 135 | } 136 | 137 | /** 138 | * 字符串截取 139 | * @param str 截取的字符串 140 | * @param len 截取的长度 141 | * @return 截取之后字符串 142 | */ 143 | public static String subStr(String str, Integer len) { 144 | if (null == len) { 145 | len = 100; 146 | } 147 | String tempStr = null; 148 | if (str.length() > len) { 149 | tempStr = str.substring(0,len); 150 | return tempStr + "..."; 151 | } 152 | return str; 153 | } 154 | 155 | /** 156 | * 截取字符串 157 | * 158 | * @param str 159 | * @param len 160 | * @return 161 | */ 162 | public static String substr(String str, int len) { 163 | if (str.length() > len) { 164 | return str.substring(0, len); 165 | } 166 | return str; 167 | } 168 | 169 | /** 170 | * 显示文章内容,转换markdown为HTML 171 | * @param value 172 | * @return 173 | */ 174 | public static String article(String value) { 175 | if (StringUtils.isNotBlank(value)) { 176 | value = value.replace("", "\r\n"); 177 | value = value.replace("", "\r\n"); 178 | return TaleUtils.mdToHtml(value); 179 | } 180 | return ""; 181 | } 182 | 183 | /** 184 | * An :grinning:awesome :smiley:string 😄with a few :wink:emojis! 185 | *

186 | * 这种格式的字符转换为emoji表情 187 | * 188 | * @param value 189 | * @return 190 | */ 191 | public static String emoji(String value) { 192 | return EmojiParser.parseToUnicode(value); 193 | } 194 | 195 | 196 | /** 197 | * 获取社交的链接地址 198 | * @return 199 | */ 200 | public static Map social() { 201 | final String prefix = "social_"; 202 | Map map = new HashMap<>(); 203 | map.put("csdn", WebConst.initConfig.get(prefix + "csdn")); 204 | map.put("jianshu", WebConst.initConfig.get(prefix + "jianshu")); 205 | map.put("resume", WebConst.initConfig.get(prefix + "resume")); 206 | map.put("weibo", WebConst.initConfig.get(prefix + "weibo")); 207 | map.put("zhihu", WebConst.initConfig.get(prefix + "zhihu")); 208 | map.put("github", WebConst.initConfig.get(prefix + "github")); 209 | map.put("twitter", WebConst.initConfig.get(prefix + "twitter")); 210 | return map; 211 | } 212 | 213 | /** 214 | * 判断分页中是否有数据 215 | * @param pageInfo 216 | * @return 217 | */ 218 | public static boolean is_empty(PageInfo pageInfo) { 219 | return pageInfo == null || (pageInfo.getList() == null) || (pageInfo.getList().size() == 0); 220 | } 221 | 222 | 223 | 224 | } 225 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | 4 | import com.github.pagehelper.PageInfo; 5 | import com.wip.constant.LogActions; 6 | import com.wip.constant.WebConst; 7 | import com.wip.controller.BaseController; 8 | import com.wip.dto.StatisticsDto; 9 | import com.wip.exception.BusinessException; 10 | import com.wip.model.CommentDomain; 11 | import com.wip.model.ContentDomain; 12 | import com.wip.model.LogDomain; 13 | import com.wip.model.UserDomain; 14 | import com.wip.service.log.LogService; 15 | import com.wip.service.site.SiteService; 16 | import com.wip.service.user.UserService; 17 | import com.wip.utils.APIResponse; 18 | import com.wip.utils.GsonUtils; 19 | import com.wip.utils.TaleUtils; 20 | import io.swagger.annotations.Api; 21 | import io.swagger.annotations.ApiOperation; 22 | import org.apache.commons.lang3.StringUtils; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.stereotype.Controller; 27 | import org.springframework.web.bind.annotation.*; 28 | 29 | import javax.servlet.http.HttpServletRequest; 30 | import javax.servlet.http.HttpSession; 31 | import java.util.List; 32 | 33 | 34 | @Api("后台首页") 35 | @Controller("adminIndexController") 36 | @RequestMapping(value = "/admin") 37 | public class IndexController extends BaseController { 38 | 39 | private static final Logger LOGGER = LoggerFactory.getLogger(IndexController.class); 40 | 41 | @Autowired 42 | private UserService userService; 43 | 44 | @Autowired 45 | private LogService logService; 46 | 47 | @Autowired 48 | private SiteService siteService; 49 | 50 | 51 | @ApiOperation("进入首页") 52 | @GetMapping(value = {"","/index"}) 53 | public String index(HttpServletRequest request) { 54 | LOGGER.info("Enter admin index method"); 55 | // 获取5条评论 56 | List comments = siteService.getComments(5); 57 | // 获取5篇文章 58 | List contents = siteService.getNewArticles(5); 59 | // 获取后台统计数 60 | StatisticsDto statistics = siteService.getStatistics(); 61 | 62 | // 获取5篇日志 63 | PageInfo logs = logService.getLogs(1,5); 64 | List list = logs.getList(); 65 | 66 | request.setAttribute("comments",comments); 67 | request.setAttribute("articles",contents); 68 | request.setAttribute("statistics",statistics); 69 | request.setAttribute("logs",list); 70 | LOGGER.info("Exit admin index method"); 71 | return "admin/index"; 72 | } 73 | 74 | /** 75 | * 个人设置页面 76 | */ 77 | @GetMapping(value = "/profile") 78 | public String profile() { 79 | return "admin/profile"; 80 | } 81 | 82 | 83 | /** 84 | * 保存个人信息 85 | * @param screenName 用户名称 86 | * @param email 邮箱 87 | * @param request 请求对象 88 | * @param session 请求session 89 | * @return 90 | */ 91 | @PostMapping(value = "/profile") 92 | @ResponseBody 93 | public APIResponse saveProfile( 94 | @RequestParam String screenName, 95 | @RequestParam String email, 96 | HttpServletRequest request, 97 | HttpSession session 98 | ) { 99 | UserDomain users = this.user(request); 100 | if (StringUtils.isNotBlank(screenName) && StringUtils.isNotBlank(email)) { 101 | UserDomain temp = new UserDomain(); 102 | temp.setUid(users.getUid()); 103 | temp.setScreenName(screenName); 104 | temp.setEmail(email); 105 | // 更新数据 106 | userService.updateUserInfo(temp); 107 | // 写入日志 108 | logService.addLog(LogActions.UP_INFO.getAction(),GsonUtils.toJsonString(temp),request.getRemoteAddr(),this.getUid(request)); 109 | 110 | // 更新session中的数据 111 | UserDomain originAL = (UserDomain) session.getAttribute(WebConst.LOGIN_SESSION_KEY); 112 | originAL.setScreenName(screenName); 113 | originAL.setEmail(email); 114 | session.setAttribute(WebConst.LOGIN_SESSION_KEY, originAL); 115 | } 116 | return APIResponse.success(); 117 | } 118 | 119 | /** 120 | * 修改密码 121 | * @param oldPassword 参数旧密码 122 | * @param newPassword 参数新密码 123 | * @param request 请求对象 124 | * @param session 请求session 125 | * @return 126 | */ 127 | @PostMapping(value = "/password") 128 | @ResponseBody 129 | public APIResponse upPwd( 130 | @RequestParam String oldPassword, 131 | @RequestParam String newPassword, 132 | HttpServletRequest request, 133 | HttpSession session 134 | ) { 135 | UserDomain users = this.user(request); 136 | if (StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) { 137 | return APIResponse.fail("请确认信息输入完整"); 138 | } 139 | 140 | if (!users.getPassword().equals(TaleUtils.MD5encode(users.getUsername() + oldPassword))) { 141 | return APIResponse.fail("旧密码错误"); 142 | } 143 | 144 | if (newPassword.length() < 6 || newPassword.length() > 14) { 145 | return APIResponse.fail("请输入6-14位密码"); 146 | } 147 | 148 | try { 149 | UserDomain temp = new UserDomain(); 150 | temp.setUid(users.getUid()); 151 | String pwd = TaleUtils.MD5encode(users.getUsername() + newPassword); 152 | temp.setPassword(pwd); 153 | userService.updateUserInfo(temp); 154 | logService.addLog(LogActions.UP_PWD.getAction(), null,request.getRemoteAddr(),this.getUid(request)); 155 | 156 | // 更新session中的数据 157 | UserDomain originAL = (UserDomain) session.getAttribute(WebConst.LOGIN_SESSION_KEY); 158 | originAL.setPassword(pwd); 159 | session.setAttribute(WebConst.LOGIN_SESSION_KEY,originAL); 160 | return APIResponse.success(); 161 | } catch (Exception e) { 162 | String msg = "密码修改失败"; 163 | if (e instanceof BusinessException) { 164 | msg = e.getMessage(); 165 | } else { 166 | LOGGER.error(msg,e); 167 | } 168 | return APIResponse.fail(msg); 169 | } 170 | } 171 | 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/article/impl/ContentServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/25 16:50 5 | **/ 6 | package com.wip.service.article.impl; 7 | 8 | import com.github.pagehelper.PageHelper; 9 | import com.github.pagehelper.PageInfo; 10 | import com.wip.constant.ErrorConstant; 11 | import com.wip.constant.Types; 12 | import com.wip.constant.WebConst; 13 | import com.wip.dao.CommentDao; 14 | import com.wip.dao.ContentDao; 15 | import com.wip.dao.RelationShipDao; 16 | import com.wip.dto.cond.ContentCond; 17 | import com.wip.exception.BusinessException; 18 | import com.wip.model.CommentDomain; 19 | import com.wip.model.ContentDomain; 20 | import com.wip.model.MetaDomain; 21 | import com.wip.model.RelationShipDomain; 22 | import com.wip.service.article.ContentService; 23 | import com.wip.service.meta.MetaService; 24 | import org.apache.commons.lang3.StringUtils; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.cache.annotation.CacheEvict; 27 | import org.springframework.cache.annotation.Cacheable; 28 | import org.springframework.stereotype.Service; 29 | import org.springframework.transaction.annotation.Transactional; 30 | 31 | import java.util.List; 32 | 33 | @Service 34 | public class ContentServiceImpl implements ContentService { 35 | 36 | @Autowired 37 | private ContentDao contentDao; 38 | 39 | @Autowired 40 | private MetaService metaService; 41 | 42 | @Autowired 43 | private RelationShipDao relationShipDao; 44 | 45 | @Autowired 46 | private CommentDao commentDao; 47 | 48 | @Transactional 49 | @Override 50 | @CacheEvict(value = {"articleCache", "articleCaches"}, allEntries = true, beforeInvocation = true) 51 | public void addArticle(ContentDomain contentDomain) { 52 | if (null == contentDomain) 53 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 54 | 55 | if (StringUtils.isBlank(contentDomain.getTitle())) 56 | throw BusinessException.withErrorCode(ErrorConstant.Article.TITLE_CAN_NOT_EMPTY); 57 | 58 | if (contentDomain.getTitle().length() > WebConst.MAX_TITLE_COUNT) 59 | throw BusinessException.withErrorCode(ErrorConstant.Article.TITLE_IS_TOO_LONG); 60 | 61 | if (StringUtils.isBlank(contentDomain.getContent())) 62 | throw BusinessException.withErrorCode(ErrorConstant.Article.CONTENT_CAN_NOT_EMPTY); 63 | 64 | if (contentDomain.getContent().length() > WebConst.MAX_CONTENT_COUNT) 65 | throw BusinessException.withErrorCode(ErrorConstant.Article.CONTENT_IS_TOO_LONG); 66 | 67 | // 取到标签和分类 68 | String tags = contentDomain.getTags(); 69 | String categories = contentDomain.getCategories(); 70 | 71 | // 添加文章 72 | contentDao.addArticle(contentDomain); 73 | 74 | // 添加分类和标签 75 | int cid = contentDomain.getCid(); 76 | metaService.addMetas(cid, tags, Types.TAG.getType()); 77 | metaService.addMetas(cid, categories, Types.CATEGORY.getType()); 78 | 79 | 80 | } 81 | 82 | @Override 83 | @Cacheable(value = "articleCache", key = "'articleById_' + #p0") 84 | public ContentDomain getArticleById(Integer cid) { 85 | if (null == cid) 86 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 87 | return contentDao.getArticleById(cid); 88 | } 89 | 90 | @Override 91 | @Transactional 92 | @CacheEvict(value = {"articleCache", "articleCaches"}, allEntries = true, beforeInvocation = true) 93 | public void updateArticleById(ContentDomain contentDomain) { 94 | // 标签和分类 95 | String tags = contentDomain.getTags(); 96 | String categories = contentDomain.getCategories(); 97 | 98 | // 更新文章 99 | contentDao.updateArticleById(contentDomain); 100 | int cid = contentDomain.getCid(); 101 | relationShipDao.deleteRelationShipByCid(cid); 102 | metaService.addMetas(cid,tags,Types.TAG.getType()); 103 | metaService.addMetas(cid,categories,Types.CATEGORY.getType()); 104 | 105 | } 106 | 107 | @Override 108 | @Cacheable(value = "articleCaches", key = "'articlesByCond_' + #p1 + 'type_' + #p0.type") 109 | public PageInfo getArticlesByCond(ContentCond contentCond, int pageNum, int pageSize) { 110 | if (null == contentCond) 111 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 112 | PageHelper.startPage(pageNum,pageSize); 113 | List contents = contentDao.getArticleByCond(contentCond); 114 | PageInfo pageInfo = new PageInfo<>(contents); 115 | return pageInfo; 116 | } 117 | 118 | @Override 119 | @Transactional 120 | @CacheEvict(value = {"articleCache","articleCaches"},allEntries = true, beforeInvocation = true) 121 | public void deleteArticleById(Integer cid) { 122 | if (null == cid) 123 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 124 | // 删除文章 125 | contentDao.deleteArticleById(cid); 126 | 127 | // 同时要删除该 文章下的所有评论 128 | List comments = commentDao.getCommentByCId(cid); 129 | if (null != comments && comments.size() > 0) { 130 | comments.forEach(comment -> { 131 | commentDao.deleteComment(comment.getCoid()); 132 | }); 133 | } 134 | 135 | // 删除标签和分类关联 136 | List relationShips = relationShipDao.getRelationShipByCid(cid); 137 | if (null != relationShips && relationShips.size() > 0) { 138 | relationShipDao.deleteRelationShipByCid(cid); 139 | } 140 | 141 | 142 | } 143 | 144 | @Override 145 | @CacheEvict(value = {"articleCache","articleCaches"}, allEntries = true, beforeInvocation = true) 146 | public void updateContentByCid(ContentDomain content) { 147 | if (null != content && null != content.getCid()) { 148 | contentDao.updateArticleById(content); 149 | } 150 | } 151 | 152 | @Override 153 | @Cacheable(value = "articleCache", key = "'articleByCategory_' + #p0") 154 | public List getArticleByCategory(String category) { 155 | if (null == category) 156 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 157 | return contentDao.getArticleByCategory(category); 158 | } 159 | 160 | @Override 161 | @Cacheable(value = "articleCache", key = "'articleByTags_'+ #p0") 162 | public List getArticleByTags(MetaDomain tags) { 163 | if (null == tags) 164 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 165 | List relationShip = relationShipDao.getRelationShipByMid(tags.getMid()); 166 | if (null != relationShip && relationShip.size() > 0) { 167 | return contentDao.getArticleByTags(relationShip); 168 | } 169 | return null; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/resources/mapper/ContentMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | t_contents 8 | 9 | 10 | 11 | c.cid, c.title, c.titlePic, c.slug, c.created, c.modified, c.content, c.authorId, 12 | c.type, c.status, c.tags, c.categories, c.hits, c.commentsNum, c.allowComment, 13 | c.allowPing, c.allowFeed 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | INSERT INTO 24 | 25 | 26 | title, titlePic, slug, created, content, authorId, 27 | type, status, tags, categories, hits, commentsNum, allowComment, 28 | allowPing, allowFeed 29 | 30 | 31 | #{title, jdbcType=VARCHAR}, 32 | #{titlePic, jdbcType=VARCHAR}, 33 | #{slug, jdbcType=VARCHAR}, 34 | UNIX_TIMESTAMP(NOW()), 35 | #{content, jdbcType=LONGVARCHAR}, 36 | #{authorId, jdbcType=INTEGER}, 37 | #{type, jdbcType=VARCHAR}, 38 | #{status, jdbcType=VARCHAR}, 39 | #{tags, jdbcType=VARCHAR}, 40 | #{categories, jdbcType=VARCHAR}, 41 | #{hits, jdbcType=INTEGER}, 42 | #{commentsNum, jdbcType=INTEGER}, 43 | #{allowComment, jdbcType=INTEGER}, 44 | #{allowPing, jdbcType=INTEGER}, 45 | #{allowFeed, jdbcType=INTEGER} 46 | 47 | 48 | 49 | 50 | 58 | 59 | 60 | 61 | UPDATE 62 | 63 | 64 | 65 | title = #{title, jdbcType=VARCHAR}, 66 | 67 | 68 | titlePic = #{titlePic, jdbcType=VARCHAR}, 69 | 70 | 71 | slug = #{slug, jdbcType=VARCHAR}, 72 | 73 | 74 | content = #{content, jdbcType=LONGVARCHAR}, 75 | 76 | modified = UNIX_TIMESTAMP(NOW()), 77 | 78 | type = #{type, jdbcType=VARCHAR}, 79 | 80 | 81 | status = #{status, jdbcType=VARCHAR}, 82 | 83 | 84 | tags = #{tags, jdbcType=VARCHAR}, 85 | 86 | 87 | categories = #{categories, jdbcType=VARCHAR}, 88 | 89 | 90 | hits = #{hits, jdbcType=INTEGER}, 91 | 92 | 93 | commentsNum = #{commentsNum, jdbcType=INTEGER}, 94 | 95 | 96 | allowComment = #{allowComment, jdbcType=INTEGER}, 97 | 98 | 99 | allowPing = #{allowPing, jdbcType=INTEGER}, 100 | 101 | 102 | allowFeed = #{allowFeed, jdbcType=INTEGER}, 103 | 104 | 105 | WHERE 106 | cid = #{cid, jdbcType=INTEGER} 107 | 108 | 109 | 110 | 143 | 144 | 145 | 146 | DELETE FROM 147 | 148 | WHERE 149 | cid = #{cid, jdbcType=INTEGER} 150 | 151 | 152 | 153 | 159 | 160 | 168 | 169 | 170 | 181 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/AttachController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import cn.hutool.core.date.DateUtil; 4 | import com.github.pagehelper.PageInfo; 5 | import com.wip.api.QiNiuCloudService; 6 | import com.wip.constant.ErrorConstant; 7 | import com.wip.constant.LogActions; 8 | import com.wip.constant.Types; 9 | import com.wip.constant.WebConst; 10 | import com.wip.controller.BaseController; 11 | import com.wip.dto.AttAchDto; 12 | import com.wip.exception.BusinessException; 13 | import com.wip.model.AttAchDomain; 14 | import com.wip.model.UserDomain; 15 | import com.wip.service.attach.AttAchService; 16 | import com.wip.service.log.LogService; 17 | import com.wip.utils.APIResponse; 18 | import com.wip.utils.Commons; 19 | import com.wip.utils.TaleUtils; 20 | import io.swagger.annotations.Api; 21 | import io.swagger.annotations.ApiOperation; 22 | import io.swagger.annotations.ApiParam; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.stereotype.Controller; 27 | import org.springframework.web.bind.annotation.*; 28 | import org.springframework.web.multipart.MultipartFile; 29 | 30 | import javax.servlet.http.HttpServletRequest; 31 | import javax.servlet.http.HttpServletResponse; 32 | import javax.servlet.http.HttpSession; 33 | import java.io.File; 34 | import java.io.IOException; 35 | import java.io.InputStream; 36 | import java.util.UUID; 37 | 38 | @Api("文件管理") 39 | @Controller 40 | @RequestMapping("admin/attach") 41 | public class AttachController extends BaseController { 42 | 43 | private static final Logger LOGGER = LoggerFactory.getLogger(AttachController.class); 44 | 45 | public static final String CLASSPATH = TaleUtils.getUploadFilePath(); 46 | 47 | @Autowired 48 | private AttAchService attAchService; 49 | 50 | @Autowired 51 | private LogService logService; 52 | 53 | 54 | 55 | @ApiOperation("文件管理首页") 56 | @GetMapping(value = "") 57 | public String index( 58 | HttpServletRequest request, 59 | @ApiParam(name = "page", value = "页数", required = false) 60 | @RequestParam(name = "page", required = false, defaultValue = "1") 61 | int page, 62 | @ApiParam(name = "limit", value = "条数", required = false) 63 | @RequestParam(name = "limit", required = false, defaultValue = "12") 64 | int limit 65 | ) { 66 | PageInfo atts = attAchService.getAtts(page, limit); 67 | request.setAttribute("attachs", atts); 68 | request.setAttribute(Types.ATTACH_URL.getType(),Commons.site_option(Types.ATTACH_URL.getType(), Commons.site_url())); 69 | request.setAttribute("max_file_size", WebConst.MAX_FILE_SIZE / 1024); 70 | return "admin/attach"; 71 | } 72 | 73 | @ApiOperation("markdown文件上传") 74 | @PostMapping(value = "/uploadfile") 75 | public void fileUploadToTencentCloud( 76 | HttpServletRequest request, 77 | HttpServletResponse response, 78 | @ApiParam(name = "editormd-image-file", value = "文件数组", required = true) 79 | @RequestParam(name = "editormd-image-file", required = true) 80 | MultipartFile file 81 | ) { 82 | 83 | } 84 | 85 | 86 | @ApiOperation("多文件上传") 87 | @PostMapping(value = "upload") 88 | @ResponseBody 89 | public APIResponse filesUploadToCloud( 90 | HttpServletRequest request, 91 | HttpServletResponse response, 92 | @ApiParam(name = "file", value = "文件数组", required = true) 93 | @RequestParam(name = "file", required = true) 94 | MultipartFile[] files 95 | ) { 96 | try { 97 | request.setCharacterEncoding("UTF-8"); 98 | response.setHeader("Content-Type","text/html"); 99 | 100 | for (MultipartFile file :files) { 101 | String fKey = renamePic(file.getOriginalFilename()); 102 | String fileName = TaleUtils.getFileKey(file.getOriginalFilename().replaceFirst("/", "")); 103 | String day = DateUtil.format(DateUtil.date(), "yyyyMMdd"); 104 | String rootFilePath = System.getProperty("user.dir") + "\\files\\" + day; // 获取上传的路径 105 | File saveFile = new File(rootFilePath); 106 | if (!saveFile.exists()) { 107 | saveFile.mkdirs(); 108 | } 109 | File f = new File(rootFilePath + "/" + fKey); 110 | InputStream inputStream = file.getInputStream(); 111 | file.transferTo(f); 112 | //QiNiuCloudService.upload(file, fileName); 113 | AttAchDomain attAchDomain = new AttAchDomain(); 114 | HttpSession session = request.getSession(); 115 | UserDomain sessionUser = (UserDomain) session.getAttribute(WebConst.LOGIN_SESSION_KEY); 116 | attAchDomain.setAuthorId(sessionUser.getUid()); 117 | attAchDomain.setFtype(TaleUtils.isImage(inputStream) ? Types.IMAGE.getType() : Types.FILE.getType()); 118 | attAchDomain.setFname(rootFilePath + "/" + fKey); 119 | attAchDomain.setFkey(fKey); 120 | attAchService.addAttAch(attAchDomain); 121 | //七牛云 122 | /*String fileName = TaleUtils.getFileKey(file.getOriginalFilename().replaceFirst("/", "")); 123 | QiNiuCloudService.upload(file, fileName); 124 | AttAchDomain attAchDomain = new AttAchDomain(); 125 | HttpSession session = request.getSession(); 126 | UserDomain sessionUser = (UserDomain) session.getAttribute(WebConst.LOGIN_SESSION_KEY); 127 | attAchDomain.setAuthorId(sessionUser.getUid()); 128 | attAchDomain.setFtype(TaleUtils.isImage(file.getInputStream()) ? Types.IMAGE.getType() : Types.FILE.getType()); 129 | attAchDomain.setFname(fileName); 130 | attAchDomain.setFkey(QiNiuCloudService.QINIU_UPLOAD_SITE + fileName); 131 | attAchService.addAttAch(attAchDomain);*/ 132 | } 133 | return APIResponse.success(); 134 | 135 | } catch (IOException e) { 136 | e.printStackTrace(); 137 | throw BusinessException.withErrorCode(ErrorConstant.Att.ADD_NEW_ATT_FAIL) 138 | .withErrorMessageArguments(e.getMessage()); 139 | } 140 | 141 | } 142 | 143 | @ApiOperation("删除文件") 144 | @PostMapping(value = "/delete") 145 | @ResponseBody 146 | public APIResponse deleteFileInfo( 147 | HttpServletRequest request, 148 | @ApiParam(name = "id", value = "文件主键", required = true) 149 | @RequestParam(name = "id", required = true) 150 | Integer id 151 | ) { 152 | try { 153 | AttAchDto attach = attAchService.getAttAchById(id); 154 | if (null == attach) 155 | throw BusinessException.withErrorCode(ErrorConstant.Att.DELETE_ATT_FAIL + ": 文件不存在"); 156 | attAchService.deleteAttAch(id); 157 | // 写入日志 158 | logService.addLog(LogActions.DEL_ATTACH.getAction(),this.user(request).getUsername()+"用户",request.getRemoteAddr(),this.getUid(request)); 159 | return APIResponse.success(); 160 | } catch (Exception e) { 161 | e.printStackTrace(); 162 | throw BusinessException.withErrorCode(e.getMessage()); 163 | } 164 | } 165 | 166 | @ApiOperation(value = "生成随机文件名称") 167 | public static String renamePic(String fileName) { 168 | return UUID.randomUUID().toString().replace("-", "") + fileName.substring(fileName.lastIndexOf(".")); 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.wip 7 | my-blog 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | my-blog 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.14.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 3.0.2.RELEASE 27 | 2.0.5 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-thymeleaf 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-web 40 | 41 | 42 | 43 | org.mybatis.spring.boot 44 | mybatis-spring-boot-starter 45 | 1.3.2 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-aop 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-starter-cache 63 | 64 | 65 | 66 | mysql 67 | mysql-connector-java 68 | runtime 69 | 70 | 71 | 72 | org.apache.commons 73 | commons-lang3 74 | 3.4 75 | 76 | 77 | 78 | com.fasterxml.jackson.core 79 | jackson-core 80 | 81 | 82 | com.fasterxml.jackson.core 83 | jackson-databind 84 | 85 | 86 | com.fasterxml.jackson.datatype 87 | jackson-datatype-joda 88 | 89 | 90 | com.fasterxml.jackson.module 91 | jackson-module-parameter-names 92 | 93 | 94 | 95 | 96 | com.github.pagehelper 97 | pagehelper-spring-boot-starter 98 | 1.2.5 99 | 100 | 101 | 102 | com.alibaba 103 | druid-spring-boot-starter 104 | 1.1.9 105 | 106 | 107 | 108 | 109 | com.vdurmont 110 | emoji-java 111 | 3.2.0 112 | 113 | 114 | 115 | io.springfox 116 | springfox-swagger2 117 | 2.2.2 118 | 119 | 120 | io.springfox 121 | springfox-swagger-ui 122 | 2.2.2 123 | 124 | 125 | 126 | 127 | net.sourceforge.nekohtml 128 | nekohtml 129 | 1.9.22 130 | 131 | 132 | 133 | 134 | com.qcloud 135 | cos_api 136 | 5.2.4 137 | 138 | 139 | 140 | com.google.code.gson 141 | gson 142 | 2.8.0 143 | 144 | 145 | 146 | 147 | com.atlassian.commonmark 148 | commonmark 149 | 0.8.0 150 | 151 | 152 | 153 | com.atlassian.commonmark 154 | commonmark-ext-gfm-tables 155 | 0.8.0 156 | 157 | 158 | 159 | 160 | com.qiniu 161 | qiniu-java-sdk 162 | 7.2.11 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | javax.servlet 174 | javax.servlet-api 175 | provided 176 | 177 | 178 | 179 | 180 | cn.hutool 181 | hutool-all 182 | 5.7.20 183 | 184 | 185 | 186 | 187 | org.projectlombok 188 | lombok 189 | 1.18.22 190 | 191 | 192 | 193 | 194 | 195 | 196 | org.springframework.boot 197 | spring-boot-maven-plugin 198 | 199 | 200 | com.wip.MyBlogApplication 201 | 202 | 203 | 204 | 205 | org.apache.maven.plugins 206 | maven-compiler-plugin 207 | 208 | 1.8 209 | 1.8 210 | UTF-8 211 | 212 | 213 | 214 | 215 | blog 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /src/main/java/com/wip/utils/TaleUtils.java: -------------------------------------------------------------------------------- 1 | package com.wip.utils; 2 | 3 | import com.wip.constant.WebConst; 4 | import com.wip.controller.admin.AttachController; 5 | import com.wip.model.UserDomain; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.commonmark.Extension; 8 | import org.commonmark.ext.gfm.tables.TablesExtension; 9 | import org.commonmark.node.Node; 10 | import org.commonmark.renderer.html.HtmlRenderer; 11 | 12 | import javax.imageio.ImageIO; 13 | import javax.servlet.http.Cookie; 14 | import javax.servlet.http.HttpServletRequest; 15 | import javax.servlet.http.HttpServletResponse; 16 | import javax.servlet.http.HttpSession; 17 | import javax.swing.text.html.parser.Parser; 18 | import java.awt.*; 19 | import java.io.File; 20 | import java.io.InputStream; 21 | import java.io.UnsupportedEncodingException; 22 | import java.security.MessageDigest; 23 | import java.security.NoSuchAlgorithmException; 24 | import java.util.Arrays; 25 | import java.util.Date; 26 | import java.util.regex.Matcher; 27 | import java.util.regex.Pattern; 28 | 29 | public class TaleUtils { 30 | 31 | /** 32 | * 匹配邮箱正则 33 | */ 34 | private static final Pattern VALID_EMAIL_ADDRESS_REGEX = 35 | Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE); 36 | private static final Pattern SLUG_REGEX = Pattern.compile("^[A-Za-z0-9_-]{5,100}$", Pattern.CASE_INSENSITIVE); 37 | 38 | /** 39 | * 获取session中的用户 40 | * @param request 41 | * @return 42 | */ 43 | public static UserDomain getLoginUser(HttpServletRequest request) { 44 | HttpSession session = request.getSession(); 45 | if (null == session) { 46 | return null; 47 | } 48 | return (UserDomain) session.getAttribute(WebConst.LOGIN_SESSION_KEY); 49 | } 50 | 51 | /** 52 | * 获取cookie中的用户ID 53 | * @param request 54 | * @return 55 | */ 56 | public static Integer getCookieUid(HttpServletRequest request){ 57 | if (null != request) { 58 | Cookie cookie = cookieRaw(WebConst.USER_IN_COOKIE,request); 59 | if (cookie != null && cookie.getValue() != null) { 60 | try { 61 | String uid = Tools.deAes(cookie.getValue(), WebConst.AES_SALT); 62 | return StringUtils.isNotBlank(uid) && Tools.isNumber(uid) ? Integer.valueOf(uid) : null; 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | return null; 69 | } 70 | 71 | /** 72 | * 从cookies中获取指定cookie 73 | * @param name 名称 74 | * @param request 请求 75 | * @return cookie 76 | */ 77 | private static Cookie cookieRaw(String name, HttpServletRequest request) { 78 | Cookie[] servletCookies = request.getCookies(); 79 | if (servletCookies == null) { 80 | return null; 81 | } 82 | for (Cookie c: servletCookies) { 83 | if (c.getName().equals(name)) { 84 | return c; 85 | } 86 | } 87 | return null; 88 | } 89 | 90 | /** 91 | * 设置记住密码cookie 92 | * @param response 93 | * @param uid 94 | */ 95 | public static void setCookie(HttpServletResponse response, Integer uid) { 96 | try { 97 | String val= Tools.enAes(uid.toString(), WebConst.AES_SALT); 98 | boolean isSSL = false; 99 | Cookie cookie = new Cookie(WebConst.USER_IN_COOKIE, val); 100 | cookie.setPath("/"); 101 | cookie.setMaxAge(60 * 30); 102 | cookie.setSecure(isSSL); 103 | response.addCookie(cookie); 104 | } catch (Exception e) { 105 | e.printStackTrace(); 106 | } 107 | } 108 | 109 | /** 110 | * 获取保存文件的位置,jar所在的目录的路径 111 | * @return 112 | */ 113 | public static String getUploadFilePath() { 114 | String path = TaleUtils.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 115 | path = path.substring(1, path.length()); 116 | try { 117 | java.net.URLDecoder.decode(path, "UTF-8"); 118 | } catch (UnsupportedEncodingException e) { 119 | e.printStackTrace(); 120 | } 121 | int lastIndex = path.lastIndexOf("/") + 1; 122 | path = path.substring(0, lastIndex); 123 | File file = new File(""); 124 | return file.getAbsolutePath() + "/"; 125 | } 126 | 127 | public static String getFileKey(String name) { 128 | String prefix = "/upload/" + DateKit.dateFormat(new Date(), "yyyy/MM"); 129 | if (!new File(AttachController.CLASSPATH + prefix).exists()) { 130 | new File(AttachController.CLASSPATH + prefix).mkdirs(); 131 | } 132 | name = StringUtils.trimToNull(name); 133 | if (name == null) { 134 | return prefix + "/" + UUID.UU32() + "." + null; 135 | } else { 136 | name = name.replace('\\','/'); 137 | name = name.substring(name.lastIndexOf("/") + 1); 138 | int index = name.lastIndexOf("."); 139 | String ext = null; 140 | if (index > 0) { 141 | ext = StringUtils.trimToNull(name.substring(index + 1)); 142 | } 143 | return prefix + "/" + UUID.UU32() + "." + (ext == null ? null : (ext)); 144 | } 145 | } 146 | 147 | /** 148 | * 判断文件是否是图片类型 149 | * @param imageFile 150 | * @return 151 | */ 152 | public static boolean isImage(InputStream imageFile) { 153 | try { 154 | Image img = ImageIO.read(imageFile); 155 | if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) { 156 | return false; 157 | } 158 | return true; 159 | } catch (Exception e) { 160 | return false; 161 | 162 | } 163 | } 164 | 165 | /** 166 | * MD5加密 167 | * @param source 数据源 168 | * @return 加密字符串 169 | */ 170 | public static String MD5encode(String source) { 171 | if (StringUtils.isBlank(source)) { 172 | return null; 173 | } 174 | MessageDigest messageDigest = null; 175 | 176 | try { 177 | // 得到一个信息摘要器 178 | messageDigest = MessageDigest.getInstance("MD5"); 179 | } catch (NoSuchAlgorithmException e) { 180 | e.printStackTrace(); 181 | } 182 | 183 | byte[] encode = messageDigest.digest(source.getBytes()); 184 | StringBuffer hexString = new StringBuffer(); 185 | // 把每一个byte 做一个与运算 0xff; 186 | for (byte anEncode : encode) { 187 | // 与运算 188 | String hex = Integer.toHexString(0xff & anEncode);// 加盐 189 | if (hex.length() == 1) { 190 | hexString.append("0"); 191 | } 192 | hexString.append(hex); 193 | } 194 | // 标准的md5加密后的结果 195 | return hexString.toString(); 196 | 197 | } 198 | 199 | /** 200 | * markdown转换为html 201 | * @param markdown 202 | * @return 203 | */ 204 | public static String mdToHtml(String markdown) { 205 | if (StringUtils.isBlank(markdown)) { 206 | return ""; 207 | } 208 | java.util.List extensions = Arrays.asList(TablesExtension.create()); 209 | org.commonmark.parser.Parser parser = org.commonmark.parser.Parser.builder().extensions(extensions).build(); 210 | Node document = parser.parse(markdown); 211 | HtmlRenderer renderer = HtmlRenderer.builder().extensions(extensions).build(); 212 | String content = renderer.render(document); 213 | content = Commons.emoji(content); 214 | return content; 215 | 216 | } 217 | 218 | /** 219 | * 判断是否是邮箱 220 | * @param emailStr 221 | * @return 222 | */ 223 | public static boolean isEmail(String emailStr) { 224 | Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailStr); 225 | return matcher.find(); 226 | } 227 | 228 | /** 229 | * 验证URL地址 230 | * @param url 格式:http://blog.csdn.net:80/xyang81/article/details/7705960? 或 http://www.csdn.net:80 231 | * @return 验证成功返回true,验证失败返回false 232 | */ 233 | public static boolean isURL(String url) { 234 | String regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?"; 235 | return Pattern.matches(regex, url); 236 | } 237 | 238 | /** 239 | * 替换HTML脚本 240 | * 241 | * @param value 242 | * @return 243 | */ 244 | public static String cleanXSS(String value) { 245 | //You'll need to remove the spaces from the html entities below 246 | value = value.replaceAll("<", "<").replaceAll(">", ">"); 247 | value = value.replaceAll("\\(", "(").replaceAll("\\)", ")"); 248 | value = value.replaceAll("'", "'"); 249 | value = value.replaceAll("eval\\((.*)\\)", ""); 250 | value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); 251 | value = value.replaceAll("script", ""); 252 | return value; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/admin/ArticleController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller.admin; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.wip.constant.LogActions; 5 | import com.wip.constant.Types; 6 | import com.wip.controller.BaseController; 7 | import com.wip.dto.cond.ContentCond; 8 | import com.wip.dto.cond.MetaCond; 9 | import com.wip.model.ContentDomain; 10 | import com.wip.model.MetaDomain; 11 | import com.wip.service.article.ContentService; 12 | import com.wip.service.log.LogService; 13 | import com.wip.service.meta.MetaService; 14 | import com.wip.utils.APIResponse; 15 | import io.swagger.annotations.Api; 16 | import io.swagger.annotations.ApiOperation; 17 | import io.swagger.annotations.ApiParam; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.stereotype.Controller; 22 | import org.springframework.web.bind.annotation.*; 23 | 24 | import javax.servlet.http.HttpServletRequest; 25 | import java.util.List; 26 | 27 | @Api("文章管理") 28 | @Controller 29 | @RequestMapping("/admin/article") 30 | public class ArticleController extends BaseController { 31 | 32 | private static final Logger LOGGER = LoggerFactory.getLogger(ArticleController.class); 33 | 34 | @Autowired 35 | private MetaService metaService; 36 | 37 | @Autowired 38 | private ContentService contentService; 39 | 40 | @Autowired 41 | private LogService logService; 42 | 43 | @ApiOperation("文章页") 44 | @GetMapping(value = "") 45 | public String index( 46 | HttpServletRequest request, 47 | @ApiParam(name = "page", value = "页数", required = false) 48 | @RequestParam(name = "page", required = false, defaultValue = "1") 49 | int page, 50 | @ApiParam(name = "limit", value = "每页数量", required = false) 51 | @RequestParam(name = "limit", required = false, defaultValue = "15") 52 | int limit 53 | ) { 54 | PageInfo articles = contentService.getArticlesByCond(new ContentCond(), page, limit); 55 | request.setAttribute("articles",articles); 56 | return "admin/article_list"; 57 | } 58 | 59 | @ApiOperation("发布新文章页") 60 | @GetMapping(value = "/publish") 61 | public String newArticle(HttpServletRequest request) { 62 | MetaCond metaCond = new MetaCond(); 63 | metaCond.setType(Types.CATEGORY.getType()); 64 | List metas = metaService.getMetas(metaCond); 65 | request.setAttribute("categories",metas); 66 | return "admin/article_edit"; 67 | } 68 | 69 | @ApiOperation("文章编辑页") 70 | @GetMapping(value = "/{cid}") 71 | public String editArticle( 72 | @ApiParam(name = "cid", value = "文章编号", required = true) 73 | @PathVariable 74 | Integer cid, 75 | HttpServletRequest request 76 | ) { 77 | ContentDomain content = contentService.getArticleById(cid); 78 | request.setAttribute("contents", content); 79 | MetaCond metaCond = new MetaCond(); 80 | metaCond.setType(Types.CATEGORY.getType()); 81 | List categories = metaService.getMetas(metaCond); 82 | request.setAttribute("categories", categories); 83 | request.setAttribute("active", "article"); 84 | return "admin/article_edit"; 85 | } 86 | 87 | @ApiOperation("编辑保存文章") 88 | @PostMapping("/modify") 89 | @ResponseBody 90 | public APIResponse modifyArticle( 91 | HttpServletRequest request, 92 | @ApiParam(name = "cid", value = "文章主键", required = true) 93 | @RequestParam(name = "cid", required = true) 94 | Integer cid, 95 | @ApiParam(name = "title", value = "标题", required = true) 96 | @RequestParam(name = "title", required = true) 97 | String title, 98 | @ApiParam(name = "titlePic", value = "标题图片", required = false) 99 | @RequestParam(name = "titlePic", required = false) 100 | String titlePic, 101 | @ApiParam(name = "slug", value = "内容缩略名", required = false) 102 | @RequestParam(name = "slug", required = false) 103 | String slug, 104 | @ApiParam(name = "content", value = "内容", required = true) 105 | @RequestParam(name = "content", required = true) 106 | String content, 107 | @ApiParam(name = "type", value = "文章类型", required = true) 108 | @RequestParam(name = "type", required = true) 109 | String type, 110 | @ApiParam(name = "status", value = "文章状态", required = true) 111 | @RequestParam(name = "status", required = true) 112 | String status, 113 | @ApiParam(name = "tags", value = "标签", required = false) 114 | @RequestParam(name = "tags", required = false) 115 | String tags, 116 | @ApiParam(name = "categories", value = "分类", required = false) 117 | @RequestParam(name = "categories", required = false, defaultValue = "默认分类") 118 | String categories, 119 | @ApiParam(name = "allowComment", value = "是否允许评论", required = true) 120 | @RequestParam(name = "allowComment", required = true) 121 | Boolean allowComment 122 | ) { 123 | ContentDomain contentDomain = new ContentDomain(); 124 | contentDomain.setTitle(title); 125 | contentDomain.setCid(cid); 126 | contentDomain.setTitlePic(titlePic); 127 | contentDomain.setSlug(slug); 128 | contentDomain.setContent(content); 129 | contentDomain.setType(type); 130 | contentDomain.setStatus(status); 131 | contentDomain.setTags(tags); 132 | contentDomain.setCategories(categories); 133 | contentDomain.setAllowComment(allowComment ? 1: 0); 134 | contentService.updateArticleById(contentDomain); 135 | 136 | return APIResponse.success(); 137 | } 138 | 139 | 140 | @ApiOperation("发布新文章") 141 | @PostMapping(value = "/publish") 142 | @ResponseBody 143 | public APIResponse publishArticle( 144 | @ApiParam(name = "title", value = "标题", required = true) 145 | @RequestParam(name = "title", required = true) 146 | String title, 147 | @ApiParam(name = "titlePic", value = "标题图片", required = false) 148 | @RequestParam(name = "titlePic", required = false) 149 | String titlePic, 150 | @ApiParam(name = "slug", value = "内容缩略名", required = false) 151 | @RequestParam(name = "slug", required = false) 152 | String slug, 153 | @ApiParam(name = "content", value = "内容", required = true) 154 | @RequestParam(name = "content", required = true) 155 | String content, 156 | @ApiParam(name = "type", value = "文章类型", required = true) 157 | @RequestParam(name = "type", required = true) 158 | String type, 159 | @ApiParam(name = "status", value = "文章状态", required = true) 160 | @RequestParam(name = "status", required = true) 161 | String status, 162 | @ApiParam(name = "categories", value = "文章分类", required = false) 163 | @RequestParam(name = "categories", required = false, defaultValue = "默认分类") 164 | String categories, 165 | @ApiParam(name = "tags", value = "文章标签", required = false) 166 | @RequestParam(name = "tags", required = false) 167 | String tags, 168 | @ApiParam(name = "allowComment", value = "是否允许评论", required = true) 169 | @RequestParam(name = "allowComment", required = true) 170 | Boolean allowComment 171 | ) { 172 | ContentDomain contentDomain = new ContentDomain(); 173 | contentDomain.setTitle(title); 174 | contentDomain.setTitlePic(titlePic); 175 | contentDomain.setSlug(slug); 176 | contentDomain.setContent(content); 177 | contentDomain.setType(type); 178 | contentDomain.setStatus(status); 179 | contentDomain.setHits(1); 180 | contentDomain.setCommentsNum(0); 181 | // 只允许博客文章有分类,防止作品被收入分类 182 | contentDomain.setTags(type.equals(Types.ARTICLE.getType()) ? tags : null); 183 | contentDomain.setCategories(type.equals(Types.ARTICLE.getType()) ? categories : null); 184 | contentDomain.setAllowComment(allowComment ? 1 : 0); 185 | 186 | // 添加文章 187 | contentService.addArticle(contentDomain); 188 | 189 | return APIResponse.success(); 190 | } 191 | 192 | @ApiOperation("删除文章") 193 | @PostMapping("/delete") 194 | @ResponseBody 195 | public APIResponse deleteArticle( 196 | @ApiParam(name = "cid", value = "文章ID", required = true) 197 | @RequestParam(name = "cid", required = true) 198 | Integer cid, 199 | HttpServletRequest request 200 | ) { 201 | // 删除文章 202 | contentService.deleteArticleById(cid); 203 | // 写入日志 204 | logService.addLog(LogActions.DEL_ARTICLE.getAction(), cid+"",request.getRemoteAddr(),this.getUid(request)); 205 | return APIResponse.success(); 206 | } 207 | 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/main/java/com/wip/service/meta/impl/MetaServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by IntelliJ IDEA. 3 | * User: Ynw 4 | * DateTime: 2018/7/24 16:43 5 | **/ 6 | package com.wip.service.meta.impl; 7 | 8 | import com.wip.constant.ErrorConstant; 9 | import com.wip.constant.Types; 10 | import com.wip.constant.WebConst; 11 | import com.wip.dao.MetaDao; 12 | import com.wip.dao.RelationShipDao; 13 | import com.wip.dto.MetaDto; 14 | import com.wip.dto.cond.MetaCond; 15 | import com.wip.exception.BusinessException; 16 | import com.wip.model.ContentDomain; 17 | import com.wip.model.MetaDomain; 18 | import com.wip.model.RelationShipDomain; 19 | import com.wip.service.article.ContentService; 20 | import com.wip.service.meta.MetaService; 21 | import org.apache.commons.lang3.StringUtils; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.cache.annotation.CacheEvict; 24 | import org.springframework.cache.annotation.Cacheable; 25 | import org.springframework.stereotype.Service; 26 | import org.springframework.transaction.annotation.Transactional; 27 | 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | 32 | /** 33 | * 项目相关Service接口实现 34 | */ 35 | @Service 36 | public class MetaServiceImpl implements MetaService { 37 | 38 | @Autowired 39 | private MetaDao metaDao; 40 | 41 | @Autowired 42 | private RelationShipDao relationShipDao; 43 | 44 | @Autowired 45 | private ContentService contentService; 46 | 47 | @Override 48 | public void saveMeta(String type, String name, Integer mid) { 49 | if (StringUtils.isNotBlank(type) && StringUtils.isNotBlank(name)) { 50 | MetaCond metaCond = new MetaCond(); 51 | metaCond.setName(name); 52 | metaCond.setType(type); 53 | // 通过项目名和类型查找有没有存在的 54 | List metas = metaDao.getMetasByCond(metaCond); 55 | // 判断是否找到有相同的 56 | if (null == metas || metas.size() ==0) { 57 | MetaDomain metaDomain = new MetaDomain(); 58 | metaDomain.setName(name); 59 | // 如果有mid代表需要更新 60 | if (null != mid) { 61 | MetaDomain meta = metaDao.getMetaById(mid); 62 | if (null != meta) 63 | metaDomain.setMid(mid); 64 | metaDao.updateMeta(metaDomain); 65 | // 更新原有的文章分类 66 | 67 | } else { 68 | // 添加分类 69 | metaDomain.setType(type); 70 | metaDao.addMeta(metaDomain); 71 | } 72 | 73 | } else { 74 | throw BusinessException.withErrorCode(ErrorConstant.Meta.META_IS_EXIST); 75 | } 76 | } 77 | } 78 | 79 | @Override 80 | @Cacheable(value = "metaCaches", key = "'metaList_'+ #p0") 81 | public List getMetaList(String type, String orderBy, int limit) { 82 | if (StringUtils.isNotBlank(type)) { 83 | if (StringUtils.isBlank(orderBy)) { 84 | orderBy = "count desc, a.mid desc"; 85 | } 86 | if (limit < 1 || limit > WebConst.MAX_POSTS) { 87 | limit = 10; 88 | } 89 | Map paraMap = new HashMap<>(); 90 | paraMap.put("type", type); 91 | paraMap.put("order", orderBy); 92 | paraMap.put("limit", limit); 93 | return metaDao.selectFromSql(paraMap); 94 | } 95 | return null; 96 | } 97 | 98 | @Override 99 | @Transactional 100 | @CacheEvict(value = {"metaCaches","metaCache"}, allEntries = true, beforeInvocation = true) 101 | public void addMetas(Integer cid, String names, String type) { 102 | if (null == cid) 103 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 104 | 105 | if (StringUtils.isNotBlank(names) && StringUtils.isNotBlank(type)) { 106 | String[] nameArr = StringUtils.split(names,","); 107 | for (String name : nameArr) { 108 | this.saveOrUpdate(cid,name,type); 109 | } 110 | } 111 | } 112 | 113 | @Override 114 | @CacheEvict(value = {"metaCaches","metaCache"}, allEntries = true,beforeInvocation = true) 115 | public void saveOrUpdate(Integer cid, String name, String type) { 116 | MetaCond metaCond = new MetaCond(); 117 | metaCond.setName(name); 118 | metaCond.setType(type); 119 | List metas = this.getMetas(metaCond); 120 | 121 | int mid; 122 | MetaDomain metaDomain; 123 | if (metas.size() == 1) { 124 | MetaDomain meta = metas.get(0); 125 | mid = meta.getMid(); 126 | } else if (metas.size() > 1) { 127 | throw BusinessException.withErrorCode(ErrorConstant.Meta.NOT_ONE_RESULT); 128 | } else { 129 | metaDomain = new MetaDomain(); 130 | metaDomain.setSlug(name); 131 | metaDomain.setName(name); 132 | metaDomain.setType(type); 133 | this.addMea(metaDomain); 134 | mid = metaDomain.getMid(); 135 | } 136 | if (mid != 0) { 137 | Long count = relationShipDao.getCountById(cid, mid); 138 | if (count ==0) { 139 | RelationShipDomain relationShip = new RelationShipDomain(); 140 | relationShip.setCid(cid); 141 | relationShip.setMid(mid); 142 | relationShipDao.addRelationShip(relationShip); 143 | } 144 | } 145 | 146 | } 147 | 148 | @Override 149 | @Transactional 150 | @CacheEvict(value = {"metaCaches","metaCache"}, allEntries = true, beforeInvocation = true) 151 | public void addMea(MetaDomain meta) { 152 | if (null == meta) 153 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 154 | metaDao.addMeta(meta); 155 | } 156 | 157 | @Override 158 | @Transactional 159 | @CacheEvict(value = {"metaCaches", "metaCache"}, allEntries = true, beforeInvocation = true) 160 | public void updateMeta(MetaDomain meta) { 161 | if (null == meta || null == meta.getMid()) 162 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 163 | metaDao.updateMeta(meta); 164 | } 165 | 166 | @Override 167 | @Cacheable(value = "metaCaches", key = "'metaCountByType_'+ #p0") 168 | public Long getMetasCountByType(String type) { 169 | if (null == type) 170 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 171 | return metaDao.getMetasCountByType(type); 172 | } 173 | 174 | @Override 175 | @Cacheable(value = "metaCaches", key = "'metaByName_' + #p0") 176 | public MetaDomain getMetaByName(String type, String name) { 177 | if (null == name) 178 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 179 | return metaDao.getMetaByName(type,name); 180 | } 181 | 182 | @Override 183 | @Transactional 184 | public void deleteMetaById(Integer mid) { 185 | if (null == mid) 186 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 187 | 188 | // 通过ID找到该项目 189 | MetaDomain meta = metaDao.getMetaById(mid); 190 | if (null != meta) { 191 | String type = meta.getType(); 192 | String name = meta.getName(); 193 | // 删除meta 194 | metaDao.deleteMetaById(mid); 195 | // 需要把相关的数据删除 196 | List relationShips = relationShipDao.getRelationShipByMid(mid); 197 | // 判断是否查找到项目编号 198 | if (null != relationShips && relationShips.size() > 0) { 199 | for (RelationShipDomain relationShip : relationShips) { 200 | // 通过关联表的文章ID找到该文章 201 | ContentDomain article = contentService.getArticleById(relationShip.getCid()); 202 | // 判断是否找到文章 203 | if (null != article) { 204 | ContentDomain temp = new ContentDomain(); 205 | temp.setCid(relationShip.getCid()); 206 | if (type.equals(Types.CATEGORY.getType())) { 207 | temp.setCategories(reMeta(name,article.getCategories())); 208 | } 209 | if (type.equals(Types.TAG.getType())) { 210 | temp.setTags(reMeta(name,article.getTags())); 211 | } 212 | // 将删除的标签和分类从文章表中去除 213 | contentService.updateArticleById(temp); 214 | } 215 | } 216 | // 删除关联meta 217 | relationShipDao.deleteRelationShipByMid(mid); 218 | } 219 | } 220 | } 221 | private String reMeta(String name, String metas) { 222 | String[] ms = StringUtils.split(metas,","); 223 | StringBuilder buf = new StringBuilder(); 224 | for (String m : ms) { 225 | if (!name.equals(m)) { 226 | buf.append(",").append(m); 227 | } 228 | } 229 | if (buf.length() > 0) { 230 | return buf.substring(1); 231 | } 232 | return ""; 233 | } 234 | 235 | @Override 236 | @Cacheable(value = "metaCaches", key = "'metas_' + #p0") 237 | public List getMetas(MetaCond metaCond) { 238 | return metaDao.getMetasByCond(metaCond); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/main/java/com/wip/controller/HomeController.java: -------------------------------------------------------------------------------- 1 | package com.wip.controller; 2 | 3 | import com.github.pagehelper.PageInfo; 4 | import com.vdurmont.emoji.EmojiParser; 5 | import com.wip.constant.ErrorConstant; 6 | import com.wip.constant.Types; 7 | import com.wip.constant.WebConst; 8 | import com.wip.dto.MetaDto; 9 | import com.wip.dto.StatisticsDto; 10 | import com.wip.dto.cond.ContentCond; 11 | import com.wip.dto.cond.MetaCond; 12 | import com.wip.exception.BusinessException; 13 | import com.wip.model.CommentDomain; 14 | import com.wip.model.ContentDomain; 15 | import com.wip.model.MetaDomain; 16 | import com.wip.service.article.ContentService; 17 | import com.wip.service.comment.CommentService; 18 | import com.wip.service.meta.MetaService; 19 | import com.wip.service.site.SiteService; 20 | import com.wip.utils.APIResponse; 21 | import com.wip.utils.IPKit; 22 | import com.wip.utils.IpInfoUtil; 23 | import com.wip.utils.TaleUtils; 24 | import io.swagger.annotations.Api; 25 | import io.swagger.annotations.ApiOperation; 26 | import io.swagger.annotations.ApiParam; 27 | import org.apache.commons.lang3.StringUtils; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.stereotype.Controller; 30 | import org.springframework.web.bind.annotation.*; 31 | 32 | import javax.servlet.http.Cookie; 33 | import javax.servlet.http.HttpServletRequest; 34 | import javax.servlet.http.HttpServletResponse; 35 | import javax.servlet.http.HttpSession; 36 | import java.net.URLEncoder; 37 | import java.util.List; 38 | 39 | @Api("博客前台页面") 40 | @Controller 41 | public class HomeController extends BaseController { 42 | 43 | @Autowired 44 | private ContentService contentService; 45 | 46 | @Autowired 47 | private CommentService commentService; 48 | 49 | @Autowired 50 | private MetaService metaService; 51 | 52 | @Autowired 53 | private IpInfoUtil ipInfoUtil; 54 | 55 | 56 | @GetMapping(value = "/") 57 | public String index( 58 | HttpServletRequest request, 59 | @ApiParam(name = "page", value = "页数", required = false) 60 | @RequestParam(name = "page", required = false, defaultValue = "1") 61 | int page, 62 | @ApiParam(name = "limit", value = "每页数量", required = false) 63 | @RequestParam(name = "limit", required = false, defaultValue = "5") 64 | int limit 65 | ) { 66 | PageInfo articles = contentService.getArticlesByCond(new ContentCond(), page, limit); 67 | 68 | request.setAttribute("articles",articles); 69 | return "blog/home"; 70 | } 71 | 72 | @ApiOperation("归档内容页") 73 | @GetMapping(value = "/archives") 74 | public String archives( 75 | HttpServletRequest request, 76 | @ApiParam(name = "page", value = "页数", required = false) 77 | @RequestParam(name = "page", required = false, defaultValue = "1") 78 | int page, 79 | @ApiParam(name = "limit", value = "每页数量", required = false) 80 | @RequestParam(name = "limit", required = false, defaultValue = "10") 81 | int limit 82 | ) { 83 | PageInfo articles = contentService.getArticlesByCond(new ContentCond(), page, limit); 84 | request.setAttribute("articles", articles); 85 | return "blog/archives"; 86 | } 87 | 88 | @ApiOperation("分类内容页") 89 | @GetMapping(value = "/categories") 90 | public String categories(HttpServletRequest request) { 91 | // 获取分类 92 | List categories = metaService.getMetaList(Types.CATEGORY.getType(),null,WebConst.MAX_POSTS); 93 | // 分类总数 94 | Long categoryCount = metaService.getMetasCountByType(Types.CATEGORY.getType()); 95 | request.setAttribute("categories", categories); 96 | request.setAttribute("categoryCount", categoryCount); 97 | return "blog/category"; 98 | } 99 | 100 | @ApiOperation("分类详情页") 101 | @GetMapping(value = "/categories/{name}") 102 | public String categoriesDetail( 103 | HttpServletRequest request, 104 | @ApiParam(name = "name", value = "分类名称", required = true) 105 | @PathVariable("name") 106 | String name 107 | ) { 108 | MetaDomain category = metaService.getMetaByName(Types.CATEGORY.getType(),name); 109 | if (null == category.getName()) { 110 | throw BusinessException.withErrorCode(ErrorConstant.Common.PARAM_IS_EMPTY); 111 | } 112 | List articles = contentService.getArticleByCategory(category.getName()); 113 | request.setAttribute("category", category.getName()); 114 | request.setAttribute("articles", articles); 115 | return "blog/category_detail"; 116 | } 117 | 118 | @ApiOperation("标签内容页") 119 | @GetMapping(value = "/tags") 120 | public String tags(HttpServletRequest request) { 121 | // 获取标签 122 | List tags = metaService.getMetaList(Types.TAG.getType(), null, WebConst.MAX_POSTS); 123 | // 标签总数 124 | Long tagCount = metaService.getMetasCountByType(Types.TAG.getType()); 125 | request.setAttribute("tags", tags); 126 | request.setAttribute("tagCount", tagCount); 127 | return "blog/tags"; 128 | } 129 | 130 | @ApiOperation("标签详情页") 131 | @GetMapping(value = "/tags/{name}") 132 | public String tagsDetail( 133 | HttpServletRequest request, 134 | @ApiParam(name = "name", value = "标签名", required = true) 135 | @PathVariable("name") 136 | String name 137 | ) { 138 | MetaDomain tags = metaService.getMetaByName(Types.TAG.getType(),name); 139 | List articles = contentService.getArticleByTags(tags); 140 | request.setAttribute("articles",articles); 141 | request.setAttribute("tags",tags.getName()); 142 | return "blog/tags_detail"; 143 | } 144 | 145 | @GetMapping(value = "/about") 146 | public String about() { 147 | return "blog/about"; 148 | } 149 | 150 | @ApiOperation("文章内容页") 151 | @GetMapping(value = "/detail/{cid}") 152 | public String detail( 153 | @ApiParam(name = "cid", value = "文章主键", required = true) 154 | @PathVariable("cid") 155 | Integer cid, 156 | HttpServletRequest request 157 | ) { 158 | ContentDomain article = contentService.getArticleById(cid); 159 | request.setAttribute("article", article); 160 | 161 | // 更新文章的点击量 162 | this.updateArticleHits(article.getCid(),article.getHits()); 163 | // 获取评论 164 | List comments = commentService.getCommentsByCId(cid); 165 | request.setAttribute("comments", comments); 166 | 167 | return "blog/detail"; 168 | } 169 | 170 | /** 171 | * 更新文章的点击率 172 | * @param cid 173 | * @param chits 174 | */ 175 | private void updateArticleHits(Integer cid, Integer chits) { 176 | Integer hits = cache.hget("article", "hits"); 177 | if (chits == null) { 178 | chits = 0; 179 | } 180 | hits = null == hits ? 1 : hits + 1; 181 | if (hits >= WebConst.HIT_EXEED) { 182 | ContentDomain temp = new ContentDomain(); 183 | temp.setCid(cid); 184 | temp.setHits(chits + hits); 185 | contentService.updateContentByCid(temp); 186 | cache.hset("article", "hits", 1); 187 | } else { 188 | cache.hset("article", "hits", hits); 189 | } 190 | 191 | } 192 | 193 | @PostMapping(value = "/comment") 194 | @ResponseBody 195 | public APIResponse comment(HttpServletRequest request, HttpServletResponse response, 196 | @RequestParam(name = "cid", required = true) Integer cid, 197 | @RequestParam(name = "coid", required = false) Integer coid, 198 | @RequestParam(name = "author", required = false) String author, 199 | @RequestParam(name = "email", required = false) String email, 200 | @RequestParam(name = "url", required = false) String url, 201 | @RequestParam(name = "content", required = true) String content, 202 | @RequestParam(name = "csrf_token", required = true) String csrf_token 203 | ) { 204 | 205 | String ref = request.getHeader("Referer"); 206 | if (StringUtils.isBlank(ref) || StringUtils.isBlank(csrf_token)){ 207 | return APIResponse.fail("访问失败"); 208 | } 209 | 210 | String token = cache.hget(Types.CSRF_TOKEN.getType(), csrf_token); 211 | if (StringUtils.isBlank(token)) { 212 | return APIResponse.fail("访问失败"); 213 | } 214 | 215 | if (null == cid || StringUtils.isBlank(content)) { 216 | return APIResponse.fail("请输入完整后评论"); 217 | } 218 | 219 | if (StringUtils.isNotBlank(author) && author.length() > 50) { 220 | return APIResponse.fail("姓名过长"); 221 | } 222 | 223 | if (StringUtils.isNotBlank(email) && !TaleUtils.isEmail(email)) { 224 | return APIResponse.fail("请输入正确的邮箱格式"); 225 | } 226 | 227 | /*if (StringUtils.isNotBlank(url) && !TaleUtils.isURL(url)) { 228 | return APIResponse.fail("请输入正确的网址格式"); 229 | }*/ 230 | 231 | if (content.length() > 200) { 232 | return APIResponse.fail("请输入200个字符以内的评价"); 233 | } 234 | 235 | String val = IPKit.getIpAddressByRequest1(request) + ":" + cid; 236 | Integer count = cache.hget(Types.COMMENTS_FREQUENCY.getType(), val); 237 | if (null != count && count > 0) { 238 | return APIResponse.fail("您发表的评论太快了,请过会再试"); 239 | } 240 | 241 | author = TaleUtils.cleanXSS(author); 242 | content = TaleUtils.cleanXSS(content); 243 | 244 | author = EmojiParser.parseToAliases(author); 245 | content = EmojiParser.parseToAliases(content); 246 | 247 | 248 | CommentDomain comments = new CommentDomain(); 249 | comments.setAuthor(author); 250 | comments.setCid(cid); 251 | url = ipInfoUtil.getIpAddr(request); 252 | comments.setIp(request.getRemoteAddr()); 253 | comments.setUrl(url); 254 | comments.setContent(content); 255 | comments.setEmail(email); 256 | comments.setParent(coid); 257 | 258 | try { 259 | commentService.addComment(comments); 260 | cookie("tale_remember_author", URLEncoder.encode(author,"UTF-8"), 7 * 24 * 60 * 60, response); 261 | cookie("tale_remember_mail", URLEncoder.encode(email,"UTF-8"), 7 * 24 * 60 * 60, response); 262 | if (StringUtils.isNotBlank(url)) { 263 | cookie("tale_remember_url",URLEncoder.encode(url,"UTF-8"),7 * 24 * 60 * 60, response); 264 | } 265 | // 设置对每个文章1分钟可以评论一次 266 | cache.hset(Types.COMMENTS_FREQUENCY.getType(),val,1,60); 267 | 268 | return APIResponse.success(); 269 | 270 | } catch (BusinessException e) { 271 | //throw BusinessException.withErrorCode(ErrorConstant.Comment.ADD_NEW_COMMENT_FAIL); 272 | throw new BusinessException(e.getErrorCode()); 273 | }catch (Exception e) { 274 | //throw BusinessException.withErrorCode(ErrorConstant.Comment.ADD_NEW_COMMENT_FAIL); 275 | throw new RuntimeException(e.getMessage()); 276 | } 277 | 278 | } 279 | 280 | private void cookie(String name, String value, int maxAge, HttpServletResponse response) { 281 | Cookie cookie = new Cookie(name,value); 282 | cookie.setMaxAge(maxAge); 283 | cookie.setSecure(false); 284 | response.addCookie(cookie); 285 | } 286 | 287 | 288 | } 289 | --------------------------------------------------------------------------------