发布文章功能开发

This commit is contained in:
x ronger 2019-11-18 01:22:27 +08:00
parent 5bce04032e
commit e19e641db4
19 changed files with 481 additions and 12 deletions

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import com.rymcu.vertical.core.exception.ServiceException; import com.rymcu.vertical.core.exception.ServiceException;
import com.rymcu.vertical.core.result.GlobalResult; import com.rymcu.vertical.core.result.GlobalResult;
import com.rymcu.vertical.core.result.ResultCode; import com.rymcu.vertical.core.result.ResultCode;
import com.rymcu.vertical.web.api.exception.MallApiException;
import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -33,7 +34,11 @@ public class HpeisExceptionHandler {
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){ public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){
if(isAjax(request)){ if(isAjax(request)){
GlobalResult result = new GlobalResult(); GlobalResult result = new GlobalResult();
if (ex instanceof UnauthenticatedException) { if (ex instanceof MallApiException){
result.setCode(401);
result.setMessage("用户未登录");
logger.info("用户未登录");
} else if (ex instanceof UnauthenticatedException) {
result.setCode(1000001); result.setCode(1000001);
result.setMessage("token错误"); result.setMessage("token错误");
logger.info("token错误"); logger.info("token错误");
@ -74,7 +79,10 @@ public class HpeisExceptionHandler {
ModelAndView mv = new ModelAndView(); ModelAndView mv = new ModelAndView();
FastJsonJsonView view = new FastJsonJsonView(); FastJsonJsonView view = new FastJsonJsonView();
Map<String, Object> attributes = new HashMap(); Map<String, Object> attributes = new HashMap();
if (ex instanceof UnauthenticatedException) { if (ex instanceof MallApiException){
attributes.put("code", "401");
attributes.put("message", "用户未登录");
} else if (ex instanceof UnauthenticatedException) {
attributes.put("code", "1000001"); attributes.put("code", "1000001");
attributes.put("message", "token错误"); attributes.put("message", "token错误");
} else if (ex instanceof UnauthorizedException) { } else if (ex instanceof UnauthorizedException) {

View File

@ -0,0 +1,40 @@
package com.rymcu.vertical.dto;
import lombok.Data;
import java.util.Date;
@Data
public class ArticleDTO {
private Integer idArticle ;
/** 文章标题 */
private String articleTitle ;
/** 文章缩略图 */
private String articleThumbnailUrl ;
/** 文章作者id */
private Integer articleAuthorId ;
/** 文章作者 */
private String articleAuthorName ;
/** 文章作者头像 */
private String articleAuthorAvatarUrl ;
/** 文章类型 */
private String articleType ;
/** 文章标签 */
private String articleTags ;
/** 浏览总数 */
private Integer articleViewCount ;
/** 预览内容 */
private Integer articlePreviewContent ;
/** 评论总数 */
private Integer commentCount ;
/** 过去时长 */
private String timeAgo ;
/** 文章永久链接 */
private String articlePermalink ;
/** 站内链接 */
private String articleLink ;
/** 更新时间 */
private Date updatedTime ;
private Author articleAuthor;
}

View File

@ -0,0 +1,16 @@
package com.rymcu.vertical.dto;
import lombok.Data;
@Data
public class Author {
private String idUser;
private String userNickname;
private String userAvatarURL;
private Integer userArticleCount;
}

View File

@ -2,6 +2,7 @@ package com.rymcu.vertical.entity;
import lombok.Data; import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import java.io.Serializable; import java.io.Serializable;
@ -11,8 +12,9 @@ import java.util.Date;
public class Article implements Serializable,Cloneable { public class Article implements Serializable,Cloneable {
/** 主键 */ /** 主键 */
@Id @Id
@GeneratedValue @GeneratedValue(generator = "JDBC")
private Integer id ; @Column(name = "id")
private Integer idArticle ;
/** 文章标题 */ /** 文章标题 */
private String articleTitle ; private String articleTitle ;
/** 文章缩略图 */ /** 文章缩略图 */
@ -29,8 +31,6 @@ public class Article implements Serializable,Cloneable {
private Integer articlePreviewContent ; private Integer articlePreviewContent ;
/** 评论总数 */ /** 评论总数 */
private Integer commentCount ; private Integer commentCount ;
/** 过去时长 */
private String timeAgo ;
/** 文章永久链接 */ /** 文章永久链接 */
private String articlePermalink ; private String articlePermalink ;
/** 站内链接 */ /** 站内链接 */

View File

@ -0,0 +1,32 @@
package com.rymcu.vertical.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.Date;
@Data
public class Tag {
/** 主键 */
@Id
@Column(name = "id")
private Integer idTag ;
/** 标签名 */
private String tagName ;
/** 标签图标 */
private String tagIconUrl ;
/** 标签uri */
private String tagUri ;
/** 描述 */
private String tagDescription ;
/** 浏览量 */
private Integer tagViewCount ;
/** 关联文章总数 */
private Integer tagArticleCount ;
/** 创建时间 */
private Date createdTime ;
/** 更新时间 */
private Date updatedTime ;
}

View File

@ -0,0 +1,21 @@
package com.rymcu.vertical.mapper;
import com.rymcu.vertical.core.mapper.Mapper;
import com.rymcu.vertical.dto.ArticleDTO;
import com.rymcu.vertical.dto.Author;
import com.rymcu.vertical.entity.Article;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ArticleMapper extends Mapper<Article> {
List<ArticleDTO> selectArticles(@Param("searchText") String searchText, @Param("tag") String tag);
Author selectAuthor(@Param("id") Integer id);
ArticleDTO selectArticleDTOById(@Param("id") Integer id);
Integer insertArticleContent(@Param("idArticle") Integer idArticle, @Param("articleContent") String articleContent, @Param("articleContentHtml") String articleContentHtml);
Integer updateArticleContent(@Param("idArticle") Integer idArticle, @Param("articleContent") String articleContent, @Param("articleContentHtml") String articleContentHtml);
}

View File

@ -0,0 +1,7 @@
package com.rymcu.vertical.mapper;
import com.rymcu.vertical.core.mapper.Mapper;
import com.rymcu.vertical.entity.Tag;
public interface TagMapper extends Mapper<Tag> {
}

View File

@ -1,7 +1,17 @@
package com.rymcu.vertical.service; package com.rymcu.vertical.service;
import com.rymcu.vertical.core.service.Service; import com.rymcu.vertical.core.service.Service;
import com.rymcu.vertical.dto.ArticleDTO;
import com.rymcu.vertical.entity.Article; import com.rymcu.vertical.entity.Article;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
public interface ArticleService extends Service<Article> { public interface ArticleService extends Service<Article> {
List<ArticleDTO> articles(String searchText, String tag);
Map postArticle(Integer idArticle, String articleTitle, String articleContent, String articleContentHtml, String articleTags, HttpServletRequest request);
ArticleDTO findArticleDTOById(Integer id);
} }

View File

@ -1,7 +1,7 @@
package com.rymcu.vertical.service; package com.rymcu.vertical.service;
import com.rymcu.vertical.core.service.Service; import com.rymcu.vertical.core.service.Service;
import com.rymcu.vertical.entity.Article; import com.rymcu.vertical.entity.Tag;
public interface TagService extends Service<Article> { public interface TagService extends Service<Tag> {
} }

View File

@ -1,10 +1,76 @@
package com.rymcu.vertical.service.impl; package com.rymcu.vertical.service.impl;
import com.rymcu.vertical.core.service.AbstractService; import com.rymcu.vertical.core.service.AbstractService;
import com.rymcu.vertical.dto.ArticleDTO;
import com.rymcu.vertical.dto.Author;
import com.rymcu.vertical.entity.Article; import com.rymcu.vertical.entity.Article;
import com.rymcu.vertical.mapper.ArticleMapper;
import com.rymcu.vertical.service.ArticleService; import com.rymcu.vertical.service.ArticleService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service @Service
public class ArticleServiceImpl extends AbstractService<Article> implements ArticleService { public class ArticleServiceImpl extends AbstractService<Article> implements ArticleService {
@Resource
private ArticleMapper articleMapper;
private static final String DOMAIN = "https://rymcu.com";
@Override
public List<ArticleDTO> articles(String searchText, String tag) {
List<ArticleDTO> list = articleMapper.selectArticles(searchText, tag);
list.forEach(article->{
article = genArticle(article);
});
return list;
}
@Override
@Transactional
public Map postArticle(Integer idArticle, String articleTitle, String articleContent, String articleContentHtml, String articleTags, HttpServletRequest request) {
Map map = new HashMap();
Article article;
if(idArticle == null || idArticle == 0){
article = new Article();
article.setArticleTitle(articleTitle);
article.setArticleAuthorId(5);
article.setArticleTags(articleTags);
article.setCreatedTime(new Date());
article.setUpdatedTime(article.getCreatedTime());
articleMapper.insertSelective(article);
article.setArticlePermalink(DOMAIN + "/article/"+article.getIdArticle());
article.setArticleLink("/article/"+article.getIdArticle());
articleMapper.insertArticleContent(article.getIdArticle(),articleContent,articleContentHtml);
} else {
article = articleMapper.selectByPrimaryKey(idArticle);
article.setArticleTitle(articleTitle);
article.setArticleTags(articleTags);
article.setUpdatedTime(new Date());
articleMapper.updateArticleContent(article.getIdArticle(),articleContent,articleContentHtml);
}
articleMapper.updateByPrimaryKeySelective(article);
map.put("id", article.getIdArticle());
return map;
}
@Override
public ArticleDTO findArticleDTOById(Integer id) {
ArticleDTO articleDTO = articleMapper.selectArticleDTOById(id);
articleDTO = genArticle(articleDTO);
return articleDTO;
}
private ArticleDTO genArticle(ArticleDTO article) {
Author author = articleMapper.selectAuthor(article.getArticleAuthorId());
article.setArticleAuthor(author);
return article;
}
} }

View File

@ -1,10 +1,10 @@
package com.rymcu.vertical.service.impl; package com.rymcu.vertical.service.impl;
import com.rymcu.vertical.core.service.AbstractService; import com.rymcu.vertical.core.service.AbstractService;
import com.rymcu.vertical.entity.Article; import com.rymcu.vertical.entity.Tag;
import com.rymcu.vertical.service.TagService; import com.rymcu.vertical.service.TagService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class TagServiceImpl extends AbstractService<Article> implements TagService { public class TagServiceImpl extends AbstractService<Tag> implements TagService {
} }

View File

@ -86,7 +86,7 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
TUser tUser = new TUser(); TUser tUser = new TUser();
BeanCopierUtil.copy(user,tUser); BeanCopierUtil.copy(user,tUser);
tUser.setToken(tokenManager.createToken(account)); tUser.setToken(tokenManager.createToken(account));
map.put("user",user); map.put("user",tUser);
} else { } else {
map.put("message","密码错误!"); map.put("message","密码错误!");
} }

View File

@ -0,0 +1,58 @@
package com.rymcu.vertical.web.api.article;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.rymcu.vertical.core.mapper.Mapper;
import com.rymcu.vertical.core.result.GlobalResult;
import com.rymcu.vertical.core.result.GlobalResultGenerator;
import com.rymcu.vertical.dto.ArticleDTO;
import com.rymcu.vertical.entity.Article;
import com.rymcu.vertical.jwt.def.JwtConstants;
import com.rymcu.vertical.service.ArticleService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/article")
public class ArticleController {
@Resource
private ArticleService articleService;
@GetMapping("/articles")
public GlobalResult articles(@RequestParam(defaultValue = "0") Integer page,@RequestParam(defaultValue = "10") Integer rows,@RequestParam(defaultValue = "") String searchText,@RequestParam(defaultValue = "") String tag){
PageHelper.startPage(page, rows);
List<ArticleDTO> list = articleService.articles(searchText,tag);
PageInfo pageInfo = new PageInfo(list);
Map map = new HashMap();
map.put("articles", pageInfo.getList());
Map pagination = new HashMap();
pagination.put("paginationPageCount",pageInfo.getPages());
pagination.put("paginationPageNums",pageInfo.getNavigatepageNums());
pagination.put("currentPage",pageInfo.getPageNum());
map.put("pagination", pagination);
return GlobalResultGenerator.genSuccessResult(map);
}
@PostMapping("/post")
public GlobalResult postArticle(@RequestParam(name = "idArticle",defaultValue = "0") Integer idArticle,@RequestParam(name = "articleTitle",defaultValue = "") String articleTitle,
@RequestParam(name = "articleContent",defaultValue = "") String articleContent,@RequestParam(name = "articleContentHtml",defaultValue = "") String articleContentHtml,
@RequestParam(name = "articleTags",defaultValue = "") String articleTags, HttpServletRequest request){
Map map = articleService.postArticle(idArticle,articleTitle,articleContent,articleContentHtml,articleTags,request);
return GlobalResultGenerator.genSuccessResult(map);
}
@GetMapping("/{id}")
public GlobalResult detail(@PathVariable Integer id){
ArticleDTO articleDTO = articleService.findArticleDTOById(id);
Map map = new HashMap<>();
map.put("article", articleDTO);
return GlobalResultGenerator.genSuccessResult(map);
}
}

View File

@ -15,7 +15,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
@RestController @RestController
@RequestMapping("/api/v1") @RequestMapping("/api/v1/console")
public class CommonApiController { public class CommonApiController {
@Resource @Resource
@ -51,4 +51,9 @@ public class CommonApiController {
Map map = userService.login(account,password); Map map = userService.login(account,password);
return GlobalResultGenerator.genSuccessResult(map); return GlobalResultGenerator.genSuccessResult(map);
} }
@GetMapping("/heartbeat")
public GlobalResult heartbeat(){
return GlobalResultGenerator.genSuccessResult("heartbeat");
}
} }

View File

@ -0,0 +1,33 @@
package com.rymcu.vertical.web.api.common;
import com.rymcu.vertical.core.result.GlobalResult;
import com.rymcu.vertical.core.result.GlobalResultGenerator;
import com.rymcu.vertical.jwt.def.JwtConstants;
import com.rymcu.vertical.web.api.exception.ErrorCode;
import com.rymcu.vertical.web.api.exception.MallApiException;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/upload")
public class UploadController {
@GetMapping("/token")
public GlobalResult uploadToken(HttpServletRequest request, @RequestParam("q") String q) throws MallApiException {
/*String authHeader = request.getHeader(JwtConstants.AUTHORIZATION);
if(StringUtils.isBlank(authHeader)){
throw new MallApiException(ErrorCode.UNAUTHORIZED);
}*/
Map map = new HashMap();
map.put("uploadToken","authHeader.hashCode()");
map.put("uploadURL","authHeader.hashCode()");
return GlobalResultGenerator.genSuccessResult(map);
}
}

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rymcu.vertical.mapper.ArticleMapper">
<resultMap id="BaseResultMap" type="com.rymcu.vertical.entity.Article">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="INTEGER" property="idArticle"/>
<result column="article_title" property="articleTitle"></result>
<result column="article_thumbnail_url" property="articleThumbnailUrl"></result>
<result column="article_author_id" property="articleAuthorId"></result>
<result column="article_type" property="articleType"></result>
<result column="article_tags" property="articleTags"></result>
<result column="article_view_count" property="articleViewCount"></result>
<result column="article_preview_content" property="articlePreviewContent"></result>
<result column="comment_count" property="commentCount"></result>
<result column="article_permalink" property="articlePermalink"></result>
<result column="article_link" property="articleLink"></result>
<result column="created_time" property="createdTime"></result>
<result column="updated_time" property="updatedTime"></result>
</resultMap>
<resultMap id="DTOResultMap" type="com.rymcu.vertical.dto.ArticleDTO">
<result column="id" property="idArticle"></result>
<result column="article_title" property="articleTitle"></result>
<result column="article_thumbnail_url" property="articleThumbnailUrl"></result>
<result column="article_author_id" property="articleAuthorId"></result>
<result column="nickname" property="articleAuthorName"></result>
<result column="avatar_url" property="articleAuthorAvatarUrl"></result>
<result column="article_type" property="articleType"></result>
<result column="article_tags" property="articleTags"></result>
<result column="article_view_count" property="articleViewCount"></result>
<result column="article_preview_content" property="articlePreviewContent"></result>
<result column="comment_count" property="commentCount"></result>
<result column="time_ago" property="timeAgo"></result>
<result column="article_permalink" property="articlePermalink"></result>
<result column="article_link" property="articleLink"></result>
<result column="updated_time" property="updatedTime"></result>
</resultMap>
<resultMap id="AuthorResultMap" type="com.rymcu.vertical.dto.Author">
<result column="id" jdbcType="VARCHAR" property="idUser"/>
<result column="nickname" jdbcType="VARCHAR" property="userNickname"/>
<result column="avatar_url" jdbcType="VARCHAR" property="userAvatarURL"/>
</resultMap>
<insert id="insertArticleContent">
insert into article_content (id_article,article_content,article_content_html,created_time,updated_time)
values (#{idArticle},#{articleContent},#{articleContentHtml},sysdate(),sysdate())
</insert>
<update id="updateArticleContent">
update article_content set article_content = #{articleContent},article_content_html = #{articleContentHtml},updated_time = sysdate() where id_article = #{idArticle}
</update>
<select id="selectArticles" resultMap="DTOResultMap">
select art.*,su.nickname,su.avatar_url from article art left join sys_user su on art.article_author_id = su.id
</select>
<select id="selectAuthor" resultMap="AuthorResultMap">
select * from sys_user where id = #{id}
</select>
<select id="selectArticleDTOById" resultMap="DTOResultMap">
select art.*,su.nickname,su.avatar_url from article art left join sys_user su on art.article_author_id = su.id where art.id = #{id}
</select>
</mapper>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.rymcu.vertical.mapper.TagMapper">
<resultMap id="BaseResultMap" type="com.rymcu.vertical.entity.Tag">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="INTEGER" property="idTag"/>
</resultMap>
</mapper>

View File

@ -0,0 +1,52 @@
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
cache: false
redis:
host: 127.0.0.1
port: 6379
password: d9d2j9w2
database: 1
timeout: 3000
jedis:
pool:
max-active: 8
max-wait: 1
max-idle: 500
min-idle: 0
datasource:
url: jdbc:mysql://101.132.182.12:3306/vertical?characterEncoding=UTF-8&autoReconnect=true&useSSL=false
username: root
password: d9d2j9w2.RYMCU
driver-class-name: com.mysql.cj.jdbc.Driver
resources:
add-mappings: true
mail:
host: smtp.ym.163.com #SMTP服务器地址
username: service@rymcu.com
password: Aa12345678
properties:
form: service@rymcu.com
wx:
miniapp:
configs:
- appid: wxf57df4f171606a26
secret: 574ff86cb48a42f3980b221e942c53b1
token: #微信小程序消息服务器配置的token
aesKey: #微信小程序消息服务器配置的EncodingAESKey
msgDataFormat: JSON
env: dev
logging:
file:
path: f:/logs/vertical
server:
port: 8099
compression:
enabled: true
mime-types: application/json,application/xml,text/html,text/xml,text/plain
min-response-size: 1024

View File

@ -0,0 +1,51 @@
spring:
profiles:
active: pord
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
cache: false
redis:
host: 127.0.0.1:6379
password: d9d2j9w2
database: 1
timeout: 3000
jedis:
pool:
max-active: 8
max-wait: 1
max-idle: 500
min-idle: 0
datasource:
url: jdbc:mysql://localhost:3306/vertical?characterEncoding=UTF-8&autoReconnect=true&useSSL=false
username: root
password: d9d2j9w2
driver-class-name: com.mysql.cj.jdbc.Driver
resources:
add-mappings: true
mail:
host: smtp.qiye.163.com #SMTP服务器地址
username: service@rymcu.com
password: 12345678Aa
properties:
form: service@rymcu.com
wx:
miniapp:
configs:
- appid: wxf57df4f171606a26
secret: 574ff86cb48a42f3980b221e942c53b1
token: #微信小程序消息服务器配置的token
aesKey: #微信小程序消息服务器配置的EncodingAESKey
msgDataFormat: JSON
env: dev
logging:
file:
path: f:/logs/vertical
server:
port: 8082
servlet:
context-path: /vertical