Merge pull request #7 from xiaohai2271/dev

最近的一些修改
This commit is contained in:
禾几海
2020-08-01 21:26:45 +08:00
committed by GitHub
38 changed files with 1166 additions and 438 deletions

View File

@@ -1,7 +1,7 @@
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path
name: Blog backEnd CI
name: Deplay
on:
push:
@@ -24,7 +24,7 @@ jobs:
java-version: 1.8
- name: Build jar file
run: echo $APPLICATION_PROPERTIES_TEST|base64 -d > src/main/resources/application-test.properties && echo $APPLICATION_PROPERTIES_PROD|base64 -d> src/main/resources/application-prod.properties && mvn -B package --file pom.xml
run: echo $APPLICATION_PROPERTIES_PROD|base64 -d> src/main/resources/application-prod.properties && mvn -B package --file pom.xml
- name: SCP
uses: appleboy/scp-action@master

View File

@@ -1,7 +1,7 @@
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java#apache-maven-with-a-settings-path
name: Blog backEnd CI
name: pr Test
on:
push:
@@ -23,7 +23,7 @@ jobs:
with:
java-version: 1.8
- name: Build jar file
- name: Test
run: echo $APPLICATION_PROPERTIES_TEST|base64 -d > src/main/resources/application-test.properties && mvn -B test --file pom.xml

View File

@@ -1,6 +1,30 @@
CREATE DATABASE `t_blog`;
CREATE DATABASE if not exists `blog`;
USE t_blog;
USE blog;
CREATE TABLE `user`
(
`u_id` int not null primary key auto_increment,
`u_email` varchar(50) not null,
`u_pwd` varchar(40) not null comment '密码',
`u_email_status` boolean default false comment '邮箱验证状态',
`u_avatar` varchar(255) default null comment '用户头像',
`u_desc` tinytext COLLATE utf8mb4_unicode_ci default null comment '用户的描述',
`u_recently_landed_time` datetime default null comment '最近的登录时间',
`u_display_name` varchar(30) COLLATE utf8mb4_unicode_ci default null comment '展示的昵称',
`u_role` varchar(40) not null default 'user' comment '权限组',
`status` tinyint(1) not null default 0 comment '账户状态',
unique key `uni_user_id` (`u_id`),
unique key `uni_user_email` (`u_email`)
) comment '用户表';
CREATE TABLE `tag_category`
(
`t_id` bigint(20) primary key auto_increment,
`t_name` varchar(255) not null,
`is_category` boolean not null default true,
`is_delete` boolean not null default false comment '该数据是否被删除'
) comment '标签和分类表';
CREATE TABLE `article`
(
@@ -14,11 +38,13 @@ CREATE TABLE `article`
`a_reading_number` int default 0 comment '文章阅读数',
`a_like` int default 0 comment '文章点赞数',
`a_dislike` int default 0 comment '文章不喜欢数',
`a_category_id` int not null comment '文章分类id',
`a_category_id` bigint not null comment '文章分类id',
`a_publish_date` datetime default CURRENT_TIMESTAMP comment '文章发布时间',
`a_update_date` datetime default null comment '文章的更新时间',
`a_is_open` boolean default true comment '文章是否可见',
`is_delete` boolean not null default false comment '该数据是否被删除'
`is_delete` boolean not null default false comment '该数据是否被删除',
foreign key (a_category_id) references tag_category (t_id),
foreign key (a_author_id) references user (u_id)
) DEFAULT CHARSET = utf8mb4
COLLATE utf8mb4_general_ci,comment '文章表';
@@ -27,17 +53,10 @@ CREATE TABLE `article_tag`
`at_id` bigint(20) primary key auto_increment,
`a_id` bigint(20) not null comment '文章id',
`t_id` bigint not null comment 'tag/category 的id',
`is_delete` boolean not null default false comment '该数据是否被删除'
foreign key (a_id) references article (a_id),
foreign key (t_id) references tag_category (t_id)
) comment '文章标签表';
CREATE TABLE `tag_category`
(
`t_id` bigint(20) primary key auto_increment,
`t_name` varchar(255) not null,
`is_category` boolean not null default true,
`is_delete` boolean not null default false comment '该数据是否被删除'
) comment '标签和分类表';
CREATE TABLE `comment`
(
`co_id` bigint(20) primary key auto_increment,
@@ -56,10 +75,12 @@ CREATE TABLE `links`
`l_id` bigint(20) primary key auto_increment,
`l_name` varchar(255) COLLATE utf8mb4_unicode_ci not null comment '友站名称',
`l_is_open` boolean default true comment '是否公开',
`l_url` varchar(255) not null comment '首页地址',
`l_url` varchar(255) unique not null comment '首页地址',
`l_icon_path` varchar(255) not null comment '友链的icon地址',
`l_desc` varchar(255) COLLATE utf8mb4_unicode_ci not null comment '友链的说明描述',
`is_delete` boolean not null default false comment '该数据是否被删除'
`is_delete` boolean not null default false comment '该数据是否被删除',
`l_email` varchar(255) comment '网站管理员的邮箱',
`l_notification` boolean default false comment '是否通知了'
) comment '友站表';
CREATE TABLE `visitor`
@@ -79,23 +100,6 @@ CREATE TABLE `web_update`
`is_delete` boolean not null default false comment '该数据是否被删除'
) comment '更新内容表';
CREATE TABLE `user`
(
`u_id` int not null primary key auto_increment,
`u_email` varchar(50) not null,
`u_pwd` varchar(40) not null comment '密码',
`u_email_status` boolean default false comment '邮箱验证状态',
`u_avatar` varchar(255) default null comment '用户头像',
`u_desc` tinytext COLLATE utf8mb4_unicode_ci default null comment '用户的描述',
`u_recently_landed_time` datetime default null comment '最近的登录时间',
`u_display_name` varchar(30) COLLATE utf8mb4_unicode_ci default null comment '展示的昵称',
`u_role` varchar(40) not null default 'user' comment '权限组',
`status` tinyint(1) not null default 0 comment '账户状态',
unique key `uni_user_id` (`u_id`),
unique key `uni_user_email` (`u_email`)
) comment '用户表';
CREATE VIEW articleView
(articleId, title, summary, mdContent, url, isOriginal, readingCount, likeCount, dislikeCount,
publishDate, updateDate, isOpen,

204
dev.sql Normal file

File diff suppressed because one or more lines are too long

49
pom.xml
View File

@@ -55,12 +55,12 @@
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<!--MarkDown 2 html -->
@@ -148,6 +148,29 @@
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- OkHttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.8.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.3.72</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.42.0</version>
</dependency>
</dependencies>
<build>
@@ -157,21 +180,15 @@
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>1.3.72</version>
<executions>
<execution>
<id>pre-unit-test</id>
<id>compile</id>
<phase>process-sources</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>

View File

@@ -26,7 +26,7 @@ public class CorsConfig {
config.addAllowedOrigin("https://celess.cn");
config.addAllowedOrigin("https://www.celess.cn");
// 本地调试时的跨域
if ("dev".equals(activeModel)) {
if (!"prod".equals(activeModel)) {
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedOrigin("http://127.0.0.1:4200");
}

View File

@@ -7,6 +7,7 @@ import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@@ -25,7 +26,7 @@ public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable("dev".equals(environment))
.enable(!"prod".equals(environment))
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("cn.celess.blog"))
@@ -37,7 +38,7 @@ public class SwaggerConfig {
return new ApiInfoBuilder()
.title("小海博客的APi")
.description("小海博客的APi")
.contact("小海")
.contact(new Contact("小海", "https://www.celess.cn", "a@celess.cn"))
.version("1.0")
.build();
}

View File

@@ -56,10 +56,13 @@ public class AuthenticationFilter implements HandlerInterceptor {
return writeResponse(ResponseEnum.LOGIN_EXPIRED, response, request);
}
String email = jwtUtil.getUsernameFromToken(jwtStr);
if (!redisUtil.hasKey(email + "-login") || jwtUtil.isTokenExpired(jwtStr)) {
if (jwtUtil.isTokenExpired(jwtStr)) {
// 登陆过期
return writeResponse(ResponseEnum.LOGIN_EXPIRED, response, request);
}
if (!redisUtil.hasKey(email + "-login")) {
return writeResponse(ResponseEnum.LOGOUT, response, request);
}
String role = userService.getUserRoleByEmail(email);
if (role.equals(ROLE_USER) || role.equals(ROLE_ADMIN)) {
// 更新token

View File

@@ -3,6 +3,7 @@ package cn.celess.blog.controller;
import cn.celess.blog.enmu.ResponseEnum;
import cn.celess.blog.entity.Response;
import cn.celess.blog.entity.model.ArticleModel;
import cn.celess.blog.entity.model.PageData;
import cn.celess.blog.entity.request.ArticleReq;
import cn.celess.blog.service.ArticleService;
import cn.celess.blog.util.RedisUserUtil;
@@ -11,6 +12,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author : xiaohai
@@ -110,8 +113,9 @@ public class ArticleController {
*/
@GetMapping("/admin/articles")
public Response adminArticles(@RequestParam(name = "page", defaultValue = "1") int page,
@RequestParam(name = "count", defaultValue = "10") int count) {
return Response.success(articleService.adminArticles(count, page));
@RequestParam(name = "count", defaultValue = "10") int count,
@RequestParam(name = "deleted", defaultValue = "false") boolean deleted) {
return Response.success(articleService.adminArticles(count, page, deleted));
}
/**

View File

@@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
* @date : 2019/04/02 22:03
*/
@RestController
public class Other {
public class CommonController {
public static final Logger logger = LoggerFactory.getLogger(Object.class);
@Autowired
@@ -135,8 +135,6 @@ public class Other {
* FUCK !!!
*
* @param file 文件
* @return
* @throws IOException
*/
@PostMapping("/imgUpload")
public void upload(HttpServletRequest request, HttpServletResponse response, @RequestParam("editormd-image-file") MultipartFile file) throws IOException {
@@ -158,6 +156,7 @@ public class Other {
return;
}
String fileName = file.getOriginalFilename();
assert fileName != null;
String mime = fileName.substring(fileName.lastIndexOf("."));
if (".png".equals(mime.toLowerCase()) || ".jpg".equals(mime.toLowerCase()) ||
".jpeg".equals(mime.toLowerCase()) || ".bmp".equals(mime.toLowerCase())) {
@@ -178,11 +177,7 @@ public class Other {
public Response bingPic() {
JSONObject imageObj;
try {
imageObj = JSONObject.fromObject(HttpUtil.get("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN"));
} catch (IOException e) {
return Response.failure(null);
}
JSONArray jsonArray = imageObj.getJSONArray("images");
String imageName = jsonArray.getJSONObject(0).getString("url");
return Response.success("https://cn.bing.com" + imageName);

View File

@@ -3,6 +3,7 @@ package cn.celess.blog.controller;
import cn.celess.blog.enmu.ResponseEnum;
import cn.celess.blog.entity.PartnerSite;
import cn.celess.blog.entity.Response;
import cn.celess.blog.entity.request.LinkApplyReq;
import cn.celess.blog.entity.request.LinkReq;
import cn.celess.blog.exception.MyException;
import cn.celess.blog.service.MailService;
@@ -69,29 +70,12 @@ public class LinksController {
}
@PostMapping("/apply")
public Response apply(@RequestParam("name") String name,
@RequestParam("url") String url) {
// TODO :: 弃用发送邮件的方式。
if (name == null || name.replaceAll(" ", "").isEmpty()) {
return Response.response(ResponseEnum.PARAMETERS_ERROR, null);
public Response apply(@RequestBody() LinkApplyReq linkApplyReq) {
return Response.success(partnerSiteService.apply(linkApplyReq));
}
if (!RegexUtil.urlMatch(url)) {
return Response.response(ResponseEnum.PARAMETERS_URL_ERROR, null);
}
String applyTimeStr = redisUtil.get(request.getRemoteAddr() + "-Apply");
int applyTime = 0;
if (applyTimeStr != null) {
applyTime = Integer.parseInt(applyTimeStr);
}
if (applyTime == 10) {
throw new MyException(ResponseEnum.FAILURE.getCode(), "申请次数已达10次请2小时后重试");
}
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject("友链申请:" + name);
message.setTo("a@celess.cn");
message.setText("name:" + name + "\nurl:" + url + "\n" + DateFormatUtil.getNow());
Boolean send = mailService.send(message);
redisUtil.setEx(request.getRemoteAddr() + "-Apply", applyTime + 1 + "", 2, TimeUnit.HOURS);
return send ? Response.success("") : Response.failure("");
@PostMapping("/reapply")
public Response reapply(@RequestParam("key") String key) {
return Response.success(partnerSiteService.reapply(key));
}
}

View File

@@ -33,6 +33,7 @@ public enum ResponseEnum {
PWD_SAME(3601, "新密码与原密码相同"),
PWD_NOT_SAME(3602, "新密码与原密码不相同"),
LOGIN_EXPIRED(3700, "登陆过期"),
LOGOUT(3710, "账户已注销"),
PWD_WRONG(3800, "密码不正确"),
JWT_EXPIRED(3810, "Token过期"),
@@ -57,6 +58,9 @@ public enum ResponseEnum {
DATA_HAS_EXIST(7020, "数据已存在"),
//其他
APPLY_LINK_NO_ADD_THIS_SITE(7200, "暂未在您的网站中抓取到本站链接"),
DATA_EXPIRED(7300, "数据过期"),
CANNOT_GET_DATA(7400, "暂无法获取到数据"),
//提交更新之前,没有获取数据/,
DID_NOT_GET_THE_DATA(8020, "非法访问"),

View File

@@ -25,6 +25,10 @@ public class PartnerSite {
private Boolean delete = false;
private String email;
private Boolean notification = true;
public PartnerSite() {
}

View File

@@ -11,15 +11,15 @@ import java.io.Serializable;
* @date : 2019/03/28 15:24
*/
@Data
public class Response implements Serializable {
public class Response<T> implements Serializable {
private int code;
private String msg;
private Object result;
private T result;
public Response() {
}
public Response(int code, String msg, Object result) {
public Response(int code, String msg, T result) {
this.code = code;
this.msg = msg;
this.result = result;

View File

@@ -82,4 +82,6 @@ public class ArticleModel {
* 文章的状态 true公开 false:不公开
*/
private Boolean open;
private boolean deleted;
}

View File

@@ -20,4 +20,5 @@ public class CategoryModel {
private String name;
private List<ArticleModel> articles;
private boolean deleted;
}

View File

@@ -21,4 +21,5 @@ public class TagModel {
private List<ArticleModel> articles;
private boolean deleted;
}

View File

@@ -37,4 +37,6 @@ public class UserModel {
private String role = "user";
private String token;
private int status;
}

View File

@@ -21,4 +21,6 @@ public class WebUpdateModel {
this.info = info;
this.time = time;
}
private boolean deleted;
}

View File

@@ -0,0 +1,17 @@
package cn.celess.blog.entity.request;
import lombok.Data;
/**
* @author : xiaohai
* @date : 2020/07/31 20:50
*/
@Data
public class LinkApplyReq {
private String name;
private String email;
private String url;
private String linkUrl;
private String desc;
private String iconPath;
}

View File

@@ -39,8 +39,9 @@ public class ExceptionHandle {
public Response handle(Exception e) {
//自定义错误
if (e instanceof MyException) {
logger.debug("返回了自定义的exception,[code={},msg={}]", ((MyException) e).getCode(), e.getMessage());
return new Response(((MyException) e).getCode(), e.getMessage(), null);
MyException exception = (MyException) e;
logger.debug("返回了自定义的exception,[code={},msg={},result={}]", exception.getCode(), e.getMessage(), exception.getResult());
return new Response(exception.getCode(), e.getMessage(), exception.getResult());
}
//请求路径不支持该方法
if (e instanceof HttpRequestMethodNotSupportedException) {

View File

@@ -1,13 +1,16 @@
package cn.celess.blog.exception;
import cn.celess.blog.enmu.ResponseEnum;
import lombok.Data;
/**
* @author : xiaohai
* @date : 2019/03/28 16:56
*/
@Data
public class MyException extends RuntimeException {
private int code;
private Object result;
public MyException(int code, String msg) {
super(msg);
@@ -24,11 +27,9 @@ public class MyException extends RuntimeException {
this.code = e.getCode();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
public MyException(ResponseEnum e, String msg, Object result) {
super(e.getMsg());
this.code = e.getCode();
this.result = result;
}
}

View File

@@ -52,7 +52,7 @@ public interface ArticleService {
* @param page 数据页
* @return 分页数据
*/
PageData<ArticleModel> adminArticles(int count, int page);
PageData<ArticleModel> adminArticles(int count, int page, boolean deleted);
/**
* 获取文章状态为开放的文章

View File

@@ -2,6 +2,7 @@ package cn.celess.blog.service;
import cn.celess.blog.entity.PartnerSite;
import cn.celess.blog.entity.model.PageData;
import cn.celess.blog.entity.request.LinkApplyReq;
import cn.celess.blog.entity.request.LinkReq;
import org.springframework.stereotype.Service;
@@ -53,4 +54,19 @@ public interface PartnerSiteService {
*/
List<PartnerSite> findAll();
/**
* 申请友链
*
* @param linkApplyReq linkApplyReq
* @return linkApplyReq
*/
PartnerSite apply(LinkApplyReq linkApplyReq);
/**
* 重写申请友链
*
* @param key key
* @return msg
*/
String reapply(String key);
}

View File

@@ -22,10 +22,12 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.security.krb5.internal.PAData;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
@@ -145,7 +147,7 @@ public class ArticleServiceImpl implements ArticleService {
//删除指定文章
articleMapper.delete(articleId);
articleTagMapper.deleteByArticleId(articleId);
//articleTagMapper.deleteByArticleId(articleId);
return true;
}
@@ -273,21 +275,24 @@ public class ArticleServiceImpl implements ArticleService {
/**
* @param count 数目
* @param page 页面 默认减1
* @param page 页面
* @return PageInfo
*/
@Override
public PageData<ArticleModel> adminArticles(int count, int page) {
PageHelper.startPage(page, count, "articleId desc");
public PageData<ArticleModel> adminArticles(int count, int page, boolean deleted) {
List<Article> articleList = articleMapper.findAll();
PageData<ArticleModel> pageData = new PageData<ArticleModel>(new PageInfo<Article>(articleList));
List<ArticleModel> articleModelList = new ArrayList<>();
articleList.forEach(article -> {
ArticleModel articleModel = ModalTrans.article(article);
articleModel.setMdContent(null);
articleModelList.add(articleModel);
});
pageData.setList(articleModelList);
PageData<ArticleModel> pageData = new PageData<>(null, 0, count, page);
List<Article> collect = articleList.stream().filter(article -> article.isDeleted() == deleted).collect(Collectors.toList());
pageData.setTotal(collect.size());
List<ArticleModel> articleModels = collect.stream()
.peek(article -> article.setMdContent(null))
.map(ModalTrans::article)
.skip((page - 1) * count)
.limit(count)
.collect(Collectors.toList());
pageData.setList(articleModels);
return pageData;
}

View File

@@ -3,18 +3,30 @@ package cn.celess.blog.service.serviceimpl;
import cn.celess.blog.enmu.ResponseEnum;
import cn.celess.blog.entity.PartnerSite;
import cn.celess.blog.entity.model.PageData;
import cn.celess.blog.entity.request.LinkApplyReq;
import cn.celess.blog.entity.request.LinkReq;
import cn.celess.blog.exception.MyException;
import cn.celess.blog.mapper.PartnerMapper;
import cn.celess.blog.service.MailService;
import cn.celess.blog.service.PartnerSiteService;
import cn.celess.blog.util.HttpUtil;
import cn.celess.blog.util.JwtUtil;
import cn.celess.blog.util.RedisUtil;
import cn.celess.blog.util.RegexUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* @author : xiaohai
@@ -24,6 +36,13 @@ import java.util.List;
public class PartnerSiteServiceImpl implements PartnerSiteService {
@Autowired
PartnerMapper partnerMapper;
@Autowired
MailService mailService;
@Autowired
RedisUtil redisUtil;
private static final String SITE_NAME = "小海博客";
private static final String SITE_URL = "celess.cn";
private static final String SITE_EMAIL = "a@celess.cn";
@Override
public PartnerSite create(LinkReq reqBody) {
@@ -52,6 +71,12 @@ public class PartnerSiteServiceImpl implements PartnerSiteService {
reqBody.setUrl("http://" + reqBody.getUrl());
}
BeanUtils.copyProperties(reqBody, partnerSite);
if (reqBody.getIconPath() == null) {
partnerSite.setIconPath("");
}
if (reqBody.getDesc() == null) {
partnerSite.setDesc("");
}
partnerMapper.insert(partnerSite);
return partnerSite;
}
@@ -80,10 +105,21 @@ public class PartnerSiteServiceImpl implements PartnerSiteService {
if (!reqBody.getUrl().contains("http://") && !reqBody.getUrl().contains("https://")) {
reqBody.setUrl("http://" + reqBody.getUrl());
}
if (reqBody.isOpen() != partnerSite.getOpen() && !partnerSite.getNotification() && !StringUtils.isEmpty(partnerSite.getEmail())) {
SimpleMailMessage smm = new SimpleMailMessage();
smm.setTo(partnerSite.getEmail());
smm.setText("您的友链申请,已通过");
smm.setSubject("友链申请通过");
smm.setSentDate(new Date());
mailService.send(smm);
partnerSite.setNotification(true);
}
BeanUtils.copyProperties(reqBody, partnerSite);
partnerMapper.update(partnerSite);
partnerSite.setName(reqBody.getName());
partnerSite.setUrl(reqBody.getUrl());
partnerSite.setOpen(reqBody.isOpen());
partnerMapper.update(partnerSite);
return partnerSite;
}
@@ -102,5 +138,92 @@ public class PartnerSiteServiceImpl implements PartnerSiteService {
return all;
}
@SneakyThrows
@Override
public PartnerSite apply(LinkApplyReq linkApplyReq) {
// 空值字段
if (StringUtils.isEmpty(linkApplyReq.getName())
|| StringUtils.isEmpty(linkApplyReq.getUrl())
|| StringUtils.isEmpty(linkApplyReq.getEmail())
|| StringUtils.isEmpty(linkApplyReq.getLinkUrl())) {
throw new MyException(ResponseEnum.PARAMETERS_ERROR);
}
// 链接不合法
if (!RegexUtil.emailMatch(linkApplyReq.getEmail())) {
throw new MyException(ResponseEnum.PARAMETERS_EMAIL_ERROR);
}
if (!RegexUtil.urlMatch(linkApplyReq.getLinkUrl()) || !RegexUtil.urlMatch(linkApplyReq.getUrl())) {
throw new MyException(ResponseEnum.PARAMETERS_URL_ERROR);
}
if (!StringUtils.isEmpty(linkApplyReq.getIconPath()) && !RegexUtil.urlMatch(linkApplyReq.getIconPath())) {
throw new MyException(ResponseEnum.PARAMETERS_URL_ERROR);
}
// 非强制字段 设置空
if (StringUtils.isEmpty(linkApplyReq.getIconPath())) {
linkApplyReq.setIconPath("");
}
// 抓取页面
String resp = HttpUtil.getAfterRendering(linkApplyReq.getLinkUrl());
if (resp == null) {
throw new MyException(ResponseEnum.CANNOT_GET_DATA);
}
PartnerSite ps = new PartnerSite();
if (resp.contains(SITE_URL)) {
//包含站点
BeanUtils.copyProperties(linkApplyReq, ps);
ps.setNotification(false);
ps.setOpen(false);
boolean exists = partnerMapper.existsByUrl(linkApplyReq.getUrl());
if (!exists) {
partnerMapper.insert(ps);
} else {
ps.setId(partnerMapper.findByUrl(linkApplyReq.getUrl()).getId());
}
SimpleMailMessage smm = new SimpleMailMessage();
smm.setSubject("友链申请");
smm.setText("有一条友链申请" + (exists ? ",已存在的友链链接" : "") + "[\n" + linkApplyReq.toString() + "\n]");
smm.setTo(SITE_EMAIL);
smm.setSentDate(new Date());
mailService.send(smm);
} else {
// 不包含站点
String uuid;
ObjectMapper mapper = new ObjectMapper();
if (redisUtil.hasKey(linkApplyReq.getUrl())) {
uuid = redisUtil.get(linkApplyReq.getUrl());
if (!redisUtil.hasKey(uuid)) {
redisUtil.setEx(uuid, mapper.writeValueAsString(linkApplyReq), 10, TimeUnit.MINUTES);
}
} else {
uuid = UUID.randomUUID().toString().replaceAll("-", "");
redisUtil.setEx(uuid, mapper.writeValueAsString(linkApplyReq), 10, TimeUnit.MINUTES);
redisUtil.setEx(linkApplyReq.getUrl(), uuid, 10, TimeUnit.MINUTES);
}
throw new MyException(ResponseEnum.APPLY_LINK_NO_ADD_THIS_SITE, null, uuid);
}
return ps;
}
@SneakyThrows
@Override
public String reapply(String key) {
if (!redisUtil.hasKey(key)) {
throw new MyException(ResponseEnum.DATA_EXPIRED);
}
String s = redisUtil.get(key);
ObjectMapper mapper = new ObjectMapper();
LinkApplyReq linkApplyReq = mapper.readValue(s, LinkApplyReq.class);
if (linkApplyReq == null) {
throw new MyException(ResponseEnum.DATA_NOT_EXIST);
}
SimpleMailMessage smm = new SimpleMailMessage();
smm.setSubject("友链申请");
smm.setText("有一条未抓取到信息的友链申请,[\n" + linkApplyReq.toString() + "\n]");
smm.setTo(SITE_EMAIL);
smm.setSentDate(new Date());
mailService.send(smm);
redisUtil.delete(key);
redisUtil.delete(linkApplyReq.getUrl());
return "success";
}
}

View File

@@ -88,7 +88,6 @@ public class WebUpdateInfoServiceImpl implements WebUpdateInfoService {
JSONObject jsonObject = new JSONObject();
jsonObject.put("lastUpdateTime", DateFormatUtil.get(webUpdateInfoMapper.getLastestOne().getUpdateTime()));
jsonObject.put("lastUpdateInfo", webUpdateInfoMapper.getLastestOne().getUpdateInfo());
try {
JSONArray array = JSONArray.fromObject(HttpUtil.get("https://api.github.com/repos/xiaohai2271/blog-frontEnd/commits?page=1&per_page=1"));
JSONObject object = array.getJSONObject(0);
JSONObject commit = object.getJSONObject("commit");
@@ -98,9 +97,6 @@ public class WebUpdateInfoServiceImpl implements WebUpdateInfoService {
Instant parse = Instant.parse(commit.getJSONObject("committer").getString("date"));
jsonObject.put("committerDate", DateFormatUtil.get(Date.from(parse)));
jsonObject.put("commitUrl", "https://github.com/xiaohai2271/blog-frontEnd/tree/" + object.getString("sha"));
} catch (IOException e) {
log.info("网络请求失败{}", e.getMessage());
}
return jsonObject;
}

View File

@@ -1,12 +1,16 @@
package cn.celess.blog.util;
import java.io.BufferedReader;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.net.MalformedURLException;
import java.util.Objects;
/**
* @Author: 小海
@@ -14,8 +18,10 @@ import java.nio.charset.StandardCharsets;
* @Desc:
*/
public class HttpUtil {
private static final OkHttpClient CLIENT = new OkHttpClient();
public static String get(String urlStr) throws IOException {
/*public static String get(String urlStr) throws IOException {
StringBuffer sb = new StringBuffer();
@@ -48,4 +54,33 @@ public class HttpUtil {
}
return sb.toString();
}
*/
public static String get(String urlStr) {
Request request = new Request.Builder()
.url(urlStr)
.get()
.build();
try (Response response = CLIENT.newCall(request).execute()) {
return Objects.requireNonNull(response.body()).string();
} catch (IOException e) {
return null;
}
}
public static String getAfterRendering(String url) {
try (final WebClient webClient = new WebClient(BrowserVersion.CHROME)) {
webClient.getOptions().setCssEnabled(false);
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.getOptions().setDownloadImages(false);
webClient.getOptions().setActiveXNative(false);
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
final HtmlPage page = webClient.getPage(url);
return page.asXml();
} catch (IOException e) {
return null;
}
}
}

View File

@@ -24,6 +24,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author: 小海
@@ -99,7 +100,7 @@ public class SitemapGenerateUtil {
urlList.put("https://www.celess.cn", DateFormatUtil.getForXmlDate(new Date()));
urlList.put("https://www.celess.cn/links", DateFormatUtil.getForXmlDate(new Date()));
urlList.put("https://www.celess.cn/leaveMsg", DateFormatUtil.getForXmlDate(new Date()));
List<Article> articles = articleMapper.findAll();
List<Article> articles = articleMapper.findAll().stream().filter(article -> article.getOpen()&&!article.isDeleted()).collect(Collectors.toList());
articles.forEach(article -> {
urlList.put("https://www.celess.cn/article/" + article.getId(), DateFormatUtil.getForXmlDate(
article.getUpdateDate() == null ? article.getPublishDate() : article.getUpdateDate()));

View File

@@ -84,7 +84,6 @@
<select id="findAllByPagePath" resultMap="commentViewResultMap" parameterType="string">
select *
from commentView
# 无奈之举
<if test="toString() != null ">
where pagePath = #{pagePath}
</if>

View File

@@ -9,20 +9,26 @@
<result column="l_icon_path" property="iconPath"/>
<result column="l_desc" property="desc"/>
<result column="is_delete" property="delete"/>
<result column="l_email" property="email"/>
<result column="l_notification" property="notification"/>
</resultMap>
<insert id="insert" parameterType="cn.celess.blog.entity.PartnerSite" useGeneratedKeys="true" keyProperty="id">
insert into links (l_name, l_is_open, l_url, l_icon_path, l_desc, is_delete)
values (#{name}, #{open}, #{url}, #{iconPath}, #{desc}, false)
insert into links (l_name, l_is_open, l_url, l_icon_path, l_desc, l_email, l_notification, is_delete)
values (#{name}, #{open}, #{url}, #{iconPath}, #{desc}, #{email}, #{notification}, false)
</insert>
<update id="update" parameterType="cn.celess.blog.entity.PartnerSite">
update links set
update links
<trim prefix="set" suffixOverrides=",">
<if test="open!=null">l_is_open=#{open},</if>
<if test="iconPath!=null">l_icon_path=#{iconPath},</if>
<if test="desc!=null">l_desc=#{desc},</if>
<if test="url!=null">l_url=#{url},</if>
<if test="name!=null">l_name=#{name}</if>
<if test="name!=null">l_name=#{name},</if>
<if test="notification!=null">l_notification=#{notification},</if>
<if test="email!=null">l_email=#{email}</if>
</trim>
where l_id=#{id}
</update>

View File

@@ -154,7 +154,7 @@
<select id="findAll" resultMap="articleViewResultMap">
select *
from articleView
where isDelete = false
order by articleId desc
</select>

View File

@@ -1,30 +1,47 @@
package cn.celess.blog;
import cn.celess.blog.entity.Response;
import cn.celess.blog.entity.model.UserModel;
import cn.celess.blog.entity.request.LoginReq;
import net.sf.json.JSONObject;
import cn.celess.blog.service.MailService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.http.Cookie;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.UUID;
import static cn.celess.blog.enmu.ResponseEnum.SUCCESS;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @Author: 小海
@@ -37,10 +54,24 @@ import static org.junit.Assert.*;
@ActiveProfiles("test")
public class BaseTest {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
protected MockMvc mockMvc;
protected final static String Code = "code";
protected final static String Result = "result";
/**
* jackson 序列化/反序列化Json
*/
protected final ObjectMapper mapper = new ObjectMapper();
protected static final TypeReference<?> BOOLEAN_TYPE = new TypeReference<Response<Boolean>>() {
};
protected static final TypeReference<?> STRING_TYPE = new TypeReference<Response<String>>() {
};
protected static final TypeReference<?> OBJECT_TYPE = new TypeReference<Response<Object>>() {
};
protected static final TypeReference<?> MAP_OBJECT_TYPE = new TypeReference<Response<Map<String, Object>>>() {
};
@Autowired
private WebApplicationContext wac;
protected MockHttpSession session;
@@ -57,51 +88,232 @@ public class BaseTest {
System.out.println("==========> 测试结束 <=========");
}
/**
*  admin 权限用户登录
*
* @return token
*/
protected String adminLogin() {
try {
LoginReq req = new LoginReq();
req.setEmail("a@celess.cn");
req.setPassword("123456789");
req.setIsRememberMe(false);
JSONObject loginReq = JSONObject.fromObject(req);
String str = mockMvc.perform(MockMvcRequestBuilders.post("/login").content(loginReq.toString()).contentType("application/json"))
// .andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
String token = JSONObject.fromObject(str).getJSONObject(Result).getString("token");
req.setIsRememberMe(true);
String token = login(req);
assertNotNull(token);
return token;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* user 权限用户登录
*
* @return token
*/
protected String userLogin() {
try {
LoginReq req = new LoginReq();
req.setEmail("zh56462271@qq.com");
req.setPassword("123456789");
req.setIsRememberMe(false);
JSONObject loginReq = JSONObject.fromObject(req);
String str = mockMvc.perform(MockMvcRequestBuilders.post("/login").content(loginReq.toString()).contentType("application/json"))
// .andDo(MockMvcResultHandlers.print())
req.setIsRememberMe(true);
String token = login(req);
assertNotNull(token);
return token;
}
/**
* 登录逻辑
*
* @param req 用户信息
* @return token | null
*/
private String login(LoginReq req) {
String str = null;
try {
str = getMockData(post("/login"), null, req)
.andReturn().getResponse().getContentAsString();
String token = JSONObject.fromObject(str).getJSONObject(Result).getString("token");
Response<UserModel> response = mapper.readValue(str, new TypeReference<Response<UserModel>>() {
});
assertEquals(SUCCESS.getCode(), response.getCode());
String token = response.getResult().getToken();
assertNotNull(token);
return token;
} catch (Exception e) {
logger.error("测试登录错误");
e.printStackTrace();
return null;
}
assertNotNull(str);
return null;
}
@Test
public void test() {
// 测试登录
assertNotNull(userLogin());
assertNotNull(adminLogin());
assertNotEquals(userLogin(), adminLogin());
try {
// 测试getMockData方法
assertNotNull(getMockData(get("/headerInfo")));
getMockData((get("/headerInfo"))).andDo(result -> assertNotNull(getResponse(result, OBJECT_TYPE)));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 产生指定长度的随机字符
*
* @param len len
* @return str
*/
protected String randomStr(int len) {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
}
/**
* 产生指定长度的随机字符
*
* @return str
*/
protected String randomStr() {
return UUID.randomUUID().toString();
}
/**
* 抽离的mock请求方法
*
* @param builder MockHttpServletRequestBuilder get(...) post(...) ....
* @return 返回 ResultActions
* @throws Exception exc
*/
protected ResultActions getMockData(MockHttpServletRequestBuilder builder) throws Exception {
return getMockData(builder, null, null);
}
/**
* 抽离的mock请求方法 重载
*
* @param builder ..
* @param token 用户登录的token
* @return ..
* @throws Exception ..
*/
protected ResultActions getMockData(MockHttpServletRequestBuilder builder, String token) throws Exception {
return getMockData(builder, token, null);
}
/**
* 抽离的mock请求方法 重载
*
* @param builder ..
* @param token ..
* @param content http中发送的APPLICATION_JSON的json数据
* @return ..
* @throws Exception ..
*/
protected ResultActions getMockData(MockHttpServletRequestBuilder builder, String token, Object content) throws Exception {
// MockHttpServletRequestBuilder mockHttpServletRequestBuilder = get(url);
if (token != null) {
builder.header("Authorization", token);
}
if (content != null) {
builder.content(mapper.writeValueAsString(content)).contentType(MediaType.APPLICATION_JSON);
}
return mockMvc.perform(builder).andExpect(status().isOk());
}
protected <T> Response<T> getResponse(String json) {
return getResponse(json, OBJECT_TYPE);
}
protected <T> Response<T> getResponse(MvcResult result) {
return getResponse(result, OBJECT_TYPE);
}
/**
* 根据json 信息反序列化成Response对象
*
* @param json json
* @param <T> 泛型
* @return Response对象
*/
protected <T> Response<T> getResponse(String json, TypeReference<?> responseType) {
Response<T> response = null;
System.out.println(responseType.getType());
try {
response = mapper.readValue(json, responseType);
} catch (IOException e) {
logger.error("解析json Response对象错误json:[{}]", json);
e.printStackTrace();
}
assertNotNull(response);
return response;
}
/**
* 根据json 信息反序列化成Response对象
*
* @param result MvcResult
* @param <T> 泛型
* @return Response对象
*/
protected <T> Response<T> getResponse(MvcResult result, TypeReference<?> responseType) {
try {
return getResponse(result.getResponse().getContentAsString(), responseType);
} catch (UnsupportedEncodingException e) {
logger.error("解析json Response对象错误result:[{}]", result);
e.printStackTrace();
}
return null;
}
/**
* 修改 mailService 的实现类
*
* @param service service 类
* @param mailFiledName service 中自动注入的mailService字段名
*/
protected void mockEmailServiceInstance(Object service, String mailFiledName) {
Field mailServiceField;
try {
mailServiceField = service.getClass().getDeclaredField(mailFiledName);
mailServiceField.setAccessible(true);
mailServiceField.set(service, new TestMailServiceImpl());
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
@Slf4j
protected static class TestMailServiceImpl implements MailService {
@Override
public Boolean AsyncSend(SimpleMailMessage message) {
log.debug("异步邮件请求,SimpleMailMessage:[{}]", getJson(message));
return true;
}
@Override
public Boolean send(SimpleMailMessage message) {
log.debug("邮件请求,SimpleMailMessage:[{}]", getJson(message));
return true;
}
/**
* 转json
*
* @param o
* @return
*/
private String getJson(Object o) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(o);
} catch (JsonProcessingException e) {
return null;
}
}
}
}

View File

@@ -8,6 +8,8 @@ import cn.celess.blog.entity.model.ArticleModel;
import cn.celess.blog.entity.model.PageData;
import cn.celess.blog.entity.request.ArticleReq;
import cn.celess.blog.mapper.ArticleMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.sf.json.JSONObject;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -260,44 +262,30 @@ public class ArticleControllerTest extends BaseTest {
@Test
public void adminArticles() {
String token;
try {
// 未登录
mockMvc.perform(get("/admin/articles?page=1&count=10"))
.andExpect(status().isOk())
.andDo(result -> {
assertEquals(HAVE_NOT_LOG_IN.getCode(),
JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)
getMockData(get("/admin/articles?page=1&count=10")).andExpect(result ->
assertEquals(HAVE_NOT_LOG_IN.getCode(), mapper.readValue(result.getResponse().getContentAsString(), Response.class).getCode())
);
});
// User权限登陆
token = userLogin();
mockMvc.perform(get("/admin/articles?page=1&count=10")
.header("Authorization", token))
.andExpect(status().isOk())
.andDo(result -> {
JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString());
assertEquals(PERMISSION_ERROR.getCode(), object.getInt(Code));
});
token = adminLogin();
getMockData(get("/admin/articles?page=1&count=10"), userLogin()).andDo(result ->
assertEquals(PERMISSION_ERROR.getCode(), mapper.readValue(result.getResponse().getContentAsString(), Response.class).getCode())
);
for (int i = 0; i < 2; i++) {
// admin权限登陆
mockMvc.perform(get("/admin/articles?page=1&count=10")
.header("Authorization", token))
.andExpect(status().isOk())
.andDo(result -> {
JSONObject adminLogin = JSONObject.fromObject(result.getResponse().getContentAsString());
assertEquals(SUCCESS.getCode(), adminLogin.getInt(Code));
assertNotNull(adminLogin.getString(Result));
int finalI = i;
getMockData(get("/admin/articles?page=1&count=10&deleted=" + (i == 1)), adminLogin()).andDo(result -> {
Response<PageData<ArticleModel>> response = mapper.readValue(result.getResponse().getContentAsString(), new TypeReference<Response<PageData<ArticleModel>>>() {
});
assertEquals(SUCCESS.getCode(), response.getCode());
assertNotNull(response.getResult());
// 判断pageInfo是否包装完全
PageData<ArticleModel> pageData = (PageData<ArticleModel>) JSONObject.toBean(adminLogin.getJSONObject(Result), PageData.class);
PageData<ArticleModel> pageData = response.getResult();
assertNotEquals(0, pageData.getTotal());
assertEquals(1, pageData.getPageNum());
assertEquals(10, pageData.getPageSize());
// 内容完整
for (Object arc : pageData.getList()) {
ArticleModel a = (ArticleModel) JSONObject.toBean(JSONObject.fromObject(arc), ArticleModel.class);
for (ArticleModel a : pageData.getList()) {
assertNotNull(a.getTitle());
assertNotNull(a.getId());
assertNotNull(a.getOriginal());
@@ -306,9 +294,11 @@ public class ArticleControllerTest extends BaseTest {
assertNotNull(a.getReadingNumber());
assertNotNull(a.getLikeCount());
assertNotNull(a.getDislikeCount());
assertEquals((finalI == 1), a.isDeleted());
assertNull(a.getMdContent());
}
});
}
} catch (Exception e) {
e.printStackTrace();
}

View File

@@ -3,31 +3,43 @@ package cn.celess.blog.controller;
import cn.celess.blog.BaseTest;
import cn.celess.blog.entity.PartnerSite;
import cn.celess.blog.entity.model.PageData;
import cn.celess.blog.entity.request.LinkApplyReq;
import cn.celess.blog.entity.request.LinkReq;
import cn.celess.blog.exception.MyException;
import cn.celess.blog.mapper.PartnerMapper;
import com.github.pagehelper.PageInfo;
import cn.celess.blog.service.MailService;
import cn.celess.blog.service.PartnerSiteService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.mail.SimpleMailMessage;
import java.lang.reflect.Field;
import java.util.UUID;
import static cn.celess.blog.enmu.ResponseEnum.*;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
@Slf4j
public class LinksControllerTest extends BaseTest {
@Autowired
PartnerMapper mapper;
@Autowired
PartnerSiteService partnerSiteService;
@Test
public void create() throws Exception {
LinkReq linkReq = new LinkReq();
linkReq.setName(UUID.randomUUID().toString().substring(0, 4));
linkReq.setOpen(false);
linkReq.setUrl("https://example.com");
linkReq.setUrl("https://" + randomStr(4) + "celess.cn");
String token = adminLogin();
mockMvc.perform(
post("/admin/links/create")
@@ -47,7 +59,8 @@ public class LinksControllerTest extends BaseTest {
// https/http
linkReq.setName(UUID.randomUUID().toString().substring(0, 4));
linkReq.setOpen(false);
linkReq.setUrl("example.com");
String url = randomStr(4) + ".celess.cn";
linkReq.setUrl(url);
mockMvc.perform(
post("/admin/links/create")
.content(JSONObject.fromObject(linkReq).toString())
@@ -57,7 +70,7 @@ public class LinksControllerTest extends BaseTest {
JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString());
assertEquals(SUCCESS.getCode(), object.getInt(Code));
PartnerSite site = (PartnerSite) JSONObject.toBean(object.getJSONObject(Result), PartnerSite.class);
assertEquals("http://example.com", site.getUrl());
assertEquals("http://" + url, site.getUrl());
});
// 测试已存在的数据
@@ -76,7 +89,7 @@ public class LinksControllerTest extends BaseTest {
partnerSite.setOpen(true);
partnerSite.setDesc("");
partnerSite.setIconPath("");
partnerSite.setUrl("https://www.celess.cn");
partnerSite.setUrl("https://" + randomStr(4) + ".celess.cn");
mapper.insert(partnerSite);
PartnerSite lastest = mapper.getLastest();
assertNotNull(lastest.getId());
@@ -105,7 +118,7 @@ public class LinksControllerTest extends BaseTest {
partnerSite.setDesc("");
partnerSite.setIconPath("");
partnerSite.setDelete(false);
partnerSite.setUrl("https://www.celess.cn");
partnerSite.setUrl("https://" + randomStr(4) + ".celess.cn");
mapper.insert(partnerSite);
// 查数据
PartnerSite lastest = mapper.getLastest();
@@ -166,18 +179,83 @@ public class LinksControllerTest extends BaseTest {
}
// 手动测试
// @Test
public void apply() throws Exception {
long l = System.currentTimeMillis();
String url = "https://www.example.com";
mockMvc.perform(post("/apply?name=小海博客Api测试请忽略&url=" + url)).andDo(result -> {
assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code));
});
System.out.println("耗时:" + (System.currentTimeMillis() - l) / 1000 + "s");
url = "xxxxxxxxxm";
mockMvc.perform(post("/apply?name=小海博客Api测试请忽略&url=" + url)).andDo(result -> {
assertEquals(PARAMETERS_URL_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code));
});
@Test
public void apply() {
// 做service 层的测试
mockEmailServiceInstance(partnerSiteService, "mailService");
LinkApplyReq req = new LinkApplyReq();
req.setName(randomStr(4));
req.setUrl("https://" + randomStr(4) + ".celess.cn");
req.setIconPath("https://www.celess.cn/example.png");
req.setDesc("desc :" + randomStr());
req.setEmail(randomStr(4) + "@celess.cn");
req.setLinkUrl(req.getUrl() + "/links");
try {
// 抓取不到数据的链接
partnerSiteService.apply(req);
} catch (MyException e) {
log.debug("测试抓取不到数据");
assertEquals(CANNOT_GET_DATA.getCode(), e.getCode());
}
req.setLinkUrl("https://bing.com");
req.setUrl(req.getLinkUrl());
try {
partnerSiteService.apply(req);
} catch (MyException e) {
log.debug("测试未添加本站链接的友链申请");
assertEquals(APPLY_LINK_NO_ADD_THIS_SITE.getCode(), e.getCode());
assertNotNull(e.getResult());
try {
// 测试uuid一致性
log.debug("测试uuid一致性");
partnerSiteService.apply(req);
} catch (MyException e2) {
assertEquals(e.getResult(), e2.getResult());
}
}
log.debug("测试正常申请");
req.setLinkUrl("https://www.celess.cn");
req.setUrl(req.getLinkUrl());
PartnerSite apply = partnerSiteService.apply(req);
assertNotNull(apply);
assertNotNull(apply.getId());
}
@Test
public void reapply() {
mockEmailServiceInstance(partnerSiteService, "mailService");
try {
partnerSiteService.reapply(randomStr());
throw new AssertionError();
} catch (MyException e) {
assertEquals(DATA_EXPIRED.getCode(), e.getCode());
}
LinkApplyReq req = new LinkApplyReq();
req.setName(randomStr(4));
req.setIconPath("https://www.celess.cn/example.png");
req.setDesc("desc :" + randomStr());
req.setEmail(randomStr(4) + "@celess.cn");
req.setLinkUrl("https://bing.com");
req.setUrl(req.getLinkUrl());
String uuid = null;
try {
partnerSiteService.apply(req);
// err here
throw new AssertionError();
} catch (MyException e) {
uuid = (String) e.getResult();
String reapply = partnerSiteService.reapply(uuid);
assertEquals(reapply, "success");
}
try {
partnerSiteService.reapply(uuid);
throw new AssertionError();
} catch (MyException e) {
assertEquals(DATA_EXPIRED.getCode(), e.getCode());
}
}
}

View File

@@ -75,10 +75,8 @@ public class ArticleTagMapperTest extends BaseTest {
@Test
public void deleteMultiById() {
ArticleTag articleTag = new ArticleTag();
Article article = new Article();
article.setId(-1L);
Tag tag = new Tag();
tag.setId(1L);
Article article = articleMapper.getLastestArticle();
Tag tag = tagMapper.getLastestTag();
articleTag.setArticle(article);
articleTag.setTag(tag);
@@ -89,7 +87,7 @@ public class ArticleTagMapperTest extends BaseTest {
articleTagMapper.insert(articleTag);
articleTagMapper.insert(articleTag);
List<ArticleTag> allByArticleId = articleTagMapper.findAllByArticleId(-1L);
List<ArticleTag> allByArticleId = articleTagMapper.findAllByArticleId(article.getId());
assertTrue(allByArticleId.size() >= 6);
int lines = articleTagMapper.deleteMultiById(allByArticleId);
assertTrue(lines >= 6);

View File

@@ -35,7 +35,7 @@ public class PartnerMapperTest extends BaseTest {
partnerSite.setIconPath(randomStr(5));
partnerSite.setDesc(randomStr(5));
partnerSite.setOpen(false);
partnerSite.setUrl("www.celess.cn?random=" + randomStr(4));
partnerSite.setUrl("www.celess.cn/?random=" + randomStr(4));
assertEquals(1, partnerMapper.update(partnerSite));
}

View File

@@ -0,0 +1,22 @@
package cn.celess.blog.util;
import cn.celess.blog.BaseTest;
import cn.celess.blog.enmu.ResponseEnum;
import cn.celess.blog.entity.Response;
import org.junit.Test;
import java.util.Map;
import static org.junit.Assert.*;
public class HttpUtilTest extends BaseTest {
@Test
public void get() {
String s = HttpUtil.get("https://api.celess.cn/headerInfo");
assertNotNull(s);
Response<Map<String, Object>> response = getResponse(s, MAP_OBJECT_TYPE);
assertEquals(ResponseEnum.SUCCESS.getCode(), response.getCode());
assertNotEquals(0, response.getResult().size());
}
}