diff --git a/blog.sql b/blog.sql index 7e5c289..f7a49f2 100644 --- a/blog.sql +++ b/blog.sql @@ -72,13 +72,15 @@ CREATE TABLE `comment` 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_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 '该数据是否被删除' + `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) 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 '该数据是否被删除', + `l_email` varchar(255) comment '网站管理员的邮箱', + `l_notification` boolean default false comment '是否通知了' ) comment '友站表'; CREATE TABLE `visitor` diff --git a/pom.xml b/pom.xml index cfa39a2..63643ee 100644 --- a/pom.xml +++ b/pom.xml @@ -148,6 +148,29 @@ jjwt 0.9.1 + + + + com.squareup.okhttp3 + okhttp + 4.8.0 + + + org.jetbrains.kotlin + kotlin-stdlib + 1.3.72 + compile + + + + + net.sourceforge.htmlunit + htmlunit + 2.42.0 + + + + @@ -157,21 +180,15 @@ spring-boot-maven-plugin - org.jacoco - jacoco-maven-plugin - 0.7.9 + org.jetbrains.kotlin + kotlin-maven-plugin + 1.3.72 - pre-unit-test + compile + process-sources - prepare-agent - - - - post-unit-test - test - - report + compile diff --git a/src/main/java/cn/celess/blog/configuration/CorsConfig.java b/src/main/java/cn/celess/blog/configuration/CorsConfig.java index f2b1634..d90e4ff 100644 --- a/src/main/java/cn/celess/blog/configuration/CorsConfig.java +++ b/src/main/java/cn/celess/blog/configuration/CorsConfig.java @@ -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"); } diff --git a/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java b/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java index e2d464b..46c2970 100644 --- a/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java +++ b/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java @@ -26,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")) diff --git a/src/main/java/cn/celess/blog/controller/CommonController.java b/src/main/java/cn/celess/blog/controller/CommonController.java index 39dca2c..902ffb6 100644 --- a/src/main/java/cn/celess/blog/controller/CommonController.java +++ b/src/main/java/cn/celess/blog/controller/CommonController.java @@ -135,8 +135,6 @@ public class CommonController { * 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 CommonController { 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 CommonController { 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); - } + imageObj = JSONObject.fromObject(HttpUtil.get("https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN")); JSONArray jsonArray = imageObj.getJSONArray("images"); String imageName = jsonArray.getJSONObject(0).getString("url"); return Response.success("https://cn.bing.com" + imageName); diff --git a/src/main/java/cn/celess/blog/controller/LinksController.java b/src/main/java/cn/celess/blog/controller/LinksController.java index 943657f..fb5b599 100644 --- a/src/main/java/cn/celess/blog/controller/LinksController.java +++ b/src/main/java/cn/celess/blog/controller/LinksController.java @@ -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); - } - 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(""); + public Response apply(@RequestBody() LinkApplyReq linkApplyReq) { + return Response.success(partnerSiteService.apply(linkApplyReq)); + } + + @PostMapping("/reapply") + public Response reapply(@RequestParam("key") String key) { + return Response.success(partnerSiteService.reapply(key)); } } diff --git a/src/main/java/cn/celess/blog/enmu/ResponseEnum.java b/src/main/java/cn/celess/blog/enmu/ResponseEnum.java index 9cca273..6c98fa5 100644 --- a/src/main/java/cn/celess/blog/enmu/ResponseEnum.java +++ b/src/main/java/cn/celess/blog/enmu/ResponseEnum.java @@ -58,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, "非法访问"), diff --git a/src/main/java/cn/celess/blog/entity/PartnerSite.java b/src/main/java/cn/celess/blog/entity/PartnerSite.java index a45c477..87a26e2 100644 --- a/src/main/java/cn/celess/blog/entity/PartnerSite.java +++ b/src/main/java/cn/celess/blog/entity/PartnerSite.java @@ -25,6 +25,10 @@ public class PartnerSite { private Boolean delete = false; + private String email; + + private Boolean notification = true; + public PartnerSite() { } diff --git a/src/main/java/cn/celess/blog/entity/request/LinkApplyReq.java b/src/main/java/cn/celess/blog/entity/request/LinkApplyReq.java new file mode 100644 index 0000000..910332b --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/request/LinkApplyReq.java @@ -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; +} diff --git a/src/main/java/cn/celess/blog/exception/ExceptionHandle.java b/src/main/java/cn/celess/blog/exception/ExceptionHandle.java index a35ab64..7dc8064 100644 --- a/src/main/java/cn/celess/blog/exception/ExceptionHandle.java +++ b/src/main/java/cn/celess/blog/exception/ExceptionHandle.java @@ -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) { diff --git a/src/main/java/cn/celess/blog/exception/MyException.java b/src/main/java/cn/celess/blog/exception/MyException.java index 7c4d412..6046d4f 100644 --- a/src/main/java/cn/celess/blog/exception/MyException.java +++ b/src/main/java/cn/celess/blog/exception/MyException.java @@ -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; } } diff --git a/src/main/java/cn/celess/blog/service/PartnerSiteService.java b/src/main/java/cn/celess/blog/service/PartnerSiteService.java index 6d28b27..e76db4a 100644 --- a/src/main/java/cn/celess/blog/service/PartnerSiteService.java +++ b/src/main/java/cn/celess/blog/service/PartnerSiteService.java @@ -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 findAll(); + /** + * 申请友链 + * + * @param linkApplyReq linkApplyReq + * @return linkApplyReq + */ + PartnerSite apply(LinkApplyReq linkApplyReq); + + /** + * 重写申请友链 + * + * @param key key + * @return msg + */ + String reapply(String key); } diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java index 81302c2..af49b48 100644 --- a/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java +++ b/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java @@ -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) { @@ -86,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; } @@ -108,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"; + } } diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java index f23665a..17b53f6 100644 --- a/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java +++ b/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java @@ -88,19 +88,15 @@ 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"); - jsonObject.put("lastCommit", commit.getString("message")); - jsonObject.put("committerAuthor", commit.getJSONObject("committer").getString("name")); - SimpleDateFormat sdf = new SimpleDateFormat(); - 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()); - } + 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"); + jsonObject.put("lastCommit", commit.getString("message")); + jsonObject.put("committerAuthor", commit.getJSONObject("committer").getString("name")); + SimpleDateFormat sdf = new SimpleDateFormat(); + 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")); return jsonObject; } diff --git a/src/main/java/cn/celess/blog/util/HttpUtil.java b/src/main/java/cn/celess/blog/util/HttpUtil.java index 8c37ff0..8dcc7fb 100644 --- a/src/main/java/cn/celess/blog/util/HttpUtil.java +++ b/src/main/java/cn/celess/blog/util/HttpUtil.java @@ -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; + } + } } diff --git a/src/main/resources/mapper/PartnerSiteMapper.xml b/src/main/resources/mapper/PartnerSiteMapper.xml index d15d7ff..b763e3d 100644 --- a/src/main/resources/mapper/PartnerSiteMapper.xml +++ b/src/main/resources/mapper/PartnerSiteMapper.xml @@ -9,20 +9,26 @@ + + - 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) - update links set - l_is_open=#{open}, - l_icon_path=#{iconPath}, - l_desc=#{desc}, - l_url=#{url}, - l_name=#{name} + update links + + l_is_open=#{open}, + l_icon_path=#{iconPath}, + l_desc=#{desc}, + l_url=#{url}, + l_name=#{name}, + l_notification=#{notification}, + l_email=#{email} + where l_id=#{id} diff --git a/src/test/java/cn/celess/blog/BaseTest.java b/src/test/java/cn/celess/blog/BaseTest.java index 50bcad4..42c1cc3 100644 --- a/src/test/java/cn/celess/blog/BaseTest.java +++ b/src/test/java/cn/celess/blog/BaseTest.java @@ -4,27 +4,37 @@ 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 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.ResultActions; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; +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; @@ -44,16 +54,24 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @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"; - private static String userToken = null; - private static String adminToken = null; /** * jackson 序列化/反序列化Json */ protected final ObjectMapper mapper = new ObjectMapper(); - + protected static final TypeReference BOOLEAN_TYPE = new TypeReference>() { + }; + protected static final TypeReference STRING_TYPE = new TypeReference>() { + }; + protected static final TypeReference OBJECT_TYPE = new TypeReference>() { + }; + protected static final TypeReference MAP_OBJECT_TYPE = new TypeReference>>() { + }; @Autowired private WebApplicationContext wac; protected MockHttpSession session; @@ -76,14 +94,13 @@ public class BaseTest { * @return token */ protected String adminLogin() { - if (adminToken != null) return adminToken; LoginReq req = new LoginReq(); req.setEmail("a@celess.cn"); req.setPassword("123456789"); - req.setIsRememberMe(false); - adminToken = login(req); - assertNotNull(adminToken); - return adminToken; + req.setIsRememberMe(true); + String token = login(req); + assertNotNull(token); + return token; } /** @@ -92,14 +109,13 @@ public class BaseTest { * @return token */ protected String userLogin() { - if (userToken != null) return userToken; LoginReq req = new LoginReq(); req.setEmail("zh56462271@qq.com"); req.setPassword("123456789"); - req.setIsRememberMe(false); - userToken = login(req); - assertNotNull(userToken); - return userToken; + req.setIsRememberMe(true); + String token = login(req); + assertNotNull(token); + return token; } /** @@ -120,8 +136,10 @@ public class BaseTest { assertNotNull(token); return token; } catch (Exception e) { + logger.error("测试登录错误"); e.printStackTrace(); } + assertNotNull(str); return null; } @@ -130,9 +148,11 @@ public class BaseTest { // 测试登录 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(); } @@ -141,13 +161,21 @@ public class BaseTest { /** * 产生指定长度的随机字符 * - * @param len - * @return + * @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请求方法 @@ -191,4 +219,101 @@ public class BaseTest { } return mockMvc.perform(builder).andExpect(status().isOk()); } + + + protected Response getResponse(String json) { + return getResponse(json, OBJECT_TYPE); + } + + protected Response getResponse(MvcResult result) { + return getResponse(result, OBJECT_TYPE); + } + + /** + * 根据json 信息反序列化成Response对象 + * + * @param json json + * @param 泛型 + * @return Response对象 + */ + protected Response getResponse(String json, TypeReference responseType) { + Response 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 泛型 + * @return Response对象 + */ + protected Response 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; + } + } + } + } diff --git a/src/test/java/cn/celess/blog/controller/LinksControllerTest.java b/src/test/java/cn/celess/blog/controller/LinksControllerTest.java index b96c49b..5dcbb05 100644 --- a/src/test/java/cn/celess/blog/controller/LinksControllerTest.java +++ b/src/test/java/cn/celess/blog/controller/LinksControllerTest.java @@ -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()); + } } } \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/mapper/PartnerMapperTest.java b/src/test/java/cn/celess/blog/mapper/PartnerMapperTest.java index 478cd22..aed93aa 100644 --- a/src/test/java/cn/celess/blog/mapper/PartnerMapperTest.java +++ b/src/test/java/cn/celess/blog/mapper/PartnerMapperTest.java @@ -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)); } diff --git a/src/test/java/cn/celess/blog/util/HttpUtilTest.java b/src/test/java/cn/celess/blog/util/HttpUtilTest.java new file mode 100644 index 0000000..9743d69 --- /dev/null +++ b/src/test/java/cn/celess/blog/util/HttpUtilTest.java @@ -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> response = getResponse(s, MAP_OBJECT_TYPE); + assertEquals(ResponseEnum.SUCCESS.getCode(), response.getCode()); + assertNotEquals(0, response.getResult().size()); + } +} \ No newline at end of file