├── list ├── domains.txt ├── images.txt └── test.txt ├── .gitignore ├── .gitattributes ├── src ├── main │ ├── resources │ │ ├── application.yml │ │ ├── static │ │ │ ├── noautho.jpg │ │ │ ├── error │ │ │ │ ├── 404.html │ │ │ │ ├── 405.html │ │ │ │ ├── 500.html │ │ │ │ ├── 403.html │ │ │ │ ├── 400.html │ │ │ │ ├── 401.html │ │ │ │ ├── 502.html │ │ │ │ └── 503.html │ │ │ └── index.html │ │ └── logback-spring.xml │ └── java │ │ └── me │ │ └── ffis │ │ └── randomImage │ │ ├── pojo │ │ └── reponse │ │ │ ├── Result.java │ │ │ ├── ReponseCode.java │ │ │ └── ResultResponse.java │ │ ├── RandomImageApplication.java │ │ ├── config │ │ ├── MyWebConfig.java │ │ └── ReadListConfig.java │ │ ├── interceptor │ │ └── DomainInterceptor.java │ │ ├── service │ │ └── ImageService.java │ │ └── controller │ │ └── ImageController.java └── test │ └── java │ └── me │ └── ffis │ └── randomImage │ └── test │ └── MyTest.java ├── README.md ├── pom.xml └── LICENSE /list/domains.txt: -------------------------------------------------------------------------------- 1 | test.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # idea files 2 | .idea/ 3 | *.iml 4 | # Generated files 5 | target 6 | # Log files 7 | logs 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the project language to Java 2 | *.js linguist-language=java 3 | *.html linguist-language=java -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9090 # 服务端口 3 | # 自定义设置 4 | customize: 5 | noReferer: false # 是否允许referer为空 -------------------------------------------------------------------------------- /src/main/resources/static/noautho.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unline2/RandomImage/HEAD/src/main/resources/static/noautho.jpg -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/pojo/reponse/Result.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.pojo.reponse; 2 | 3 | /** 4 | * Created by fanfan on 2019/12/05. 5 | */ 6 | public interface Result { 7 | //操作是否成功 8 | boolean flag(); 9 | 10 | //操作代码 11 | Integer code(); 12 | 13 | //提示信息 14 | String message(); 15 | 16 | //返回信息 17 | Object data(); 18 | } 19 | -------------------------------------------------------------------------------- /list/images.txt: -------------------------------------------------------------------------------- 1 | http://img.test.com/images/bg-0.jpg 2 | http://img.test.com/images/bg-1.jpg 3 | http://img.test.com/images/bg-2.jpg 4 | http://img.test.com/images/bg-3.jpg 5 | http://img.test.com/images/bg-4.jpg 6 | http://img.test.com/images/bg-5.jpg 7 | http://img.test.com/images/bg-6.jpg 8 | http://img.test.com/images/bg-7.jpg 9 | http://img.test.com/images/bg-8.jpg 10 | http://img.test.com/images/bg-9.jpg 11 | http://img.test.com/images/bg-10.jpg 12 | -------------------------------------------------------------------------------- /list/test.txt: -------------------------------------------------------------------------------- 1 | http://img.test.com/images/bg-0.jpg 2 | http://img.test.com/images/bg-1.jpg 3 | http://img.test.com/images/bg-2.jpg 4 | http://img.test.com/images/bg-3.jpg 5 | http://img.test.com/images/bg-4.jpg 6 | http://img.test.com/images/bg-5.jpg 7 | http://img.test.com/images/bg-6.jpg 8 | http://img.test.com/images/bg-7.jpg 9 | http://img.test.com/images/bg-8.jpg 10 | http://img.test.com/images/bg-9.jpg 11 | http://img.test.com/images/bg-10.jpg 12 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/RandomImageApplication.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * 随机图片Api启动类 8 | * Created by fanfan on 2020/01/05. 9 | */ 10 | 11 | @SpringBootApplication 12 | public class RandomImageApplication { 13 | public static void main(String[] args) { 14 | SpringApplication.run(RandomImageApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/config/MyWebConfig.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.config; 2 | 3 | import me.ffis.randomImage.interceptor.DomainInterceptor; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | 9 | /** 10 | * 配置拦截器 11 | * Created by fanfan on 2020/01/07. 12 | */ 13 | 14 | @Configuration 15 | public class MyWebConfig implements WebMvcConfigurer { 16 | 17 | @Override 18 | public void addInterceptors(InterceptorRegistry registry) { 19 | registry.addInterceptor(DomainInterceptor()) 20 | .addPathPatterns("/random/**") //拦截哪些请求 21 | .addPathPatterns("/today/**") 22 | .excludePathPatterns(""); //对哪些请求不拦截 23 | } 24 | 25 | @Bean //将自定义拦截器注册到 Spring Bean 中 26 | public DomainInterceptor DomainInterceptor() { 27 | return new DomainInterceptor(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/pojo/reponse/ReponseCode.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.pojo.reponse; 2 | 3 | import lombok.ToString; 4 | 5 | /** 6 | * 枚举类封装返回常量 7 | */ 8 | @ToString 9 | public enum ReponseCode implements Result { 10 | SUCCESS(true, 100, "操作成功"), 11 | FAIL(false, 101, "操作失败"), 12 | FLUSH_SUCCESS(true, 102, "刷新缓存成功"), 13 | FLUSH_FAIL(false, 103, "刷新缓存失败"); 14 | 15 | //操作是否成功 16 | private boolean flag; 17 | //操作代码 18 | private Integer code; 19 | //提示信息 20 | private String message; 21 | //返回信息 22 | private Object data; 23 | 24 | ReponseCode(boolean flag, Integer code, String message) { 25 | this.flag = flag; 26 | this.code = code; 27 | this.message = message; 28 | } 29 | 30 | @Override 31 | public boolean flag() { 32 | return flag; 33 | } 34 | 35 | @Override 36 | public Integer code() { 37 | return code; 38 | } 39 | 40 | @Override 41 | public String message() { 42 | return message; 43 | } 44 | 45 | @Override 46 | public Object data() { 47 | return data; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/pojo/reponse/ResultResponse.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.pojo.reponse; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.ToString; 6 | 7 | /** 8 | * Created by fanfan on 2019/12/05. 9 | */ 10 | 11 | @Data 12 | @ToString 13 | @NoArgsConstructor 14 | public class ResultResponse implements Result { 15 | 16 | //操作是否成功 17 | private boolean flag; 18 | //操作代码 19 | private Integer code; 20 | //提示信息 21 | private String message; 22 | //返回数据 23 | private Object data; 24 | 25 | public ResultResponse(boolean flag, Integer code, String message) { 26 | this.flag = flag; 27 | this.code = code; 28 | this.message = message; 29 | } 30 | 31 | public ResultResponse(Result result) { 32 | this.flag = result.flag(); 33 | this.code = result.code(); 34 | this.message = result.message(); 35 | } 36 | 37 | public ResultResponse(Result result, Object data) { 38 | this.flag = result.flag(); 39 | this.code = result.code(); 40 | this.message = result.message(); 41 | this.data = data; 42 | } 43 | 44 | @Override 45 | public boolean flag() { 46 | return flag; 47 | } 48 | 49 | @Override 50 | public Integer code() { 51 | return code; 52 | } 53 | 54 | @Override 55 | public String message() { 56 | return message; 57 | } 58 | 59 | @Override 60 | public Object data() { 61 | return data; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/interceptor/DomainInterceptor.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.interceptor; 2 | 3 | import me.ffis.randomImage.config.ReadListConfig; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.web.servlet.HandlerInterceptor; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.util.List; 10 | 11 | /** 12 | * 限制白名单的域名才能访问 13 | * Created by fanfan on 2020/01/07. 14 | */ 15 | public class DomainInterceptor implements HandlerInterceptor { 16 | 17 | 18 | @Value("${customize.noReferer}") 19 | private boolean noReferer; 20 | 21 | @Override 22 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 23 | //获取请求的referer 24 | String referer = request.getHeader("referer"); 25 | if (referer == null || "".equals(referer)) { 26 | //判断是否允许referer为空访问 27 | if (!noReferer) { 28 | //referer为空转发到首页 29 | request.getRequestDispatcher("/index.html").forward(request, response); 30 | return false; 31 | } 32 | //referer为null,跳过白名单验证 33 | return true; 34 | } 35 | //取出域名白名单的list集合 36 | List list = ReadListConfig.listMap.get("domains.txt"); 37 | //如果domains.txt文件不存在或者文件为空,则不限制访问 38 | if (list == null || list.isEmpty()) { 39 | return true; 40 | } 41 | //域名在白名单,放行 42 | for (String domain : list) { 43 | if (referer.contains(domain)) { 44 | return true; 45 | } 46 | } 47 | //域名不在白名单,跳转到未授权页面 48 | response.sendRedirect("/noautho.jpg"); 49 | return false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Random-Image-Api 2 | ======== 3 | ![license] 4 | ![GitHub repo size] 5 | 6 | 7 | Random-Image-Api 一个能够获取随机图片的 Api,基于 Spring Boot 构建 8 | 9 | 可读取本地图片列表的地址,并提供随机访问服务,可配置域名白名单访问 10 | 11 | ![random-img] 12 | 13 | ### 项目说明 14 | 15 | 程序启动的时候会自动加载 `项目路径/list` 文件夹下的所有列表文件; 16 | 17 | 图片列表文件: 18 | - 提供访问路径为文件名的随机图片服务 19 | - 文件命名格式 `xxx.txt` 必须为 `.txt` 结尾,每行一个图片url 20 | 21 | 域名白名单列表文件: 22 | - 会开启域名白名单访问,只允许列表中的域名进行接口调用 23 | - 命名只能为 `domains.txt`,每行一个域名,支持泛域名 24 | - 例如输入 `test.com` ,则会允许所有 `test.com` 结尾的域名访问 25 | - 若域名列表文件不存在或者文件为空,则会关闭域名白名单服务,任何域名都可以进行调用。 26 | 27 | > 更改列表文件后,刷新图片缓存即可生效。 28 | 29 | ### 编译运行 30 | 31 | ``` 32 | # 拉取项目 33 | git clone https://github.com/noisky/Random-Image-Api.git 34 | # 使用 maven 打包 35 | mvn clean package 36 | cd target && java -jar Random-Image-Api-1.0.0.jar 37 | # 将写好的图片列表文件放入 list 文件夹,刷新缓存即可正常访问 38 | http://localhost:9090/flush 39 | # 默认访问端口 9090 40 | http://localhost:9090/random/{图片列表文件名} 41 | # 主页地址 42 | http://localhost:9090/index.html 43 | ``` 44 | ### 接口调用: 45 | 46 | 1、获取随机图片: 47 | 48 | - 请求方式:`GET请求` 49 | 50 | - 请求地址:`/random/{images}` 51 | 52 | - `{images}` 则对应为存放图片地址的文件名 `images.txt` 去掉后缀 53 | 54 | 2、获取每日图片: 55 | 56 | - 请求方式:`GET请求` 57 | 58 | - 请求地址:`/today/{images}` 59 | 60 | - `{images}` 则对应为存放图片地址的文件名 `images.txt` 去掉后缀 61 | 62 | 63 | 3、刷新图片缓存: 64 | 65 | - 请求方式:`GET请求` 66 | 67 | - 请求地址:`/flush` 68 | 69 | 70 | ### 已完成功能: 71 | 72 | - 获取每日图片 73 | 74 | - 读取本地列表的图片地址,提供随机访问 75 | 76 | - 域名白名单访问,未授权的域名访问会跳转到未授权页面 77 | 78 | 79 | ### TODO: 80 | 81 | - 提供本地图片的随机访问 82 | 83 | - 接口调用统计 84 | 85 | 86 | [license]:https://img.shields.io/github/license/noisky/Random-Image-Api?color=blue 87 | [GitHub repo size]:https://img.shields.io/github/repo-size/noisky/Random-Image-Api?logo=git 88 | [random-img]:https://img.ffis.me/images/2020/01/08/QQ20200108160257.png -------------------------------------------------------------------------------- /src/test/java/me/ffis/randomImage/test/MyTest.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.test; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Calendar; 7 | 8 | /** 9 | * Created by fanfan on 2020/01/06. 10 | */ 11 | public class MyTest { 12 | 13 | @Test 14 | public void test1() { 15 | ArrayList list = new ArrayList<>(); 16 | 17 | list.add("1"); 18 | double v = Math.random() * list.size(); 19 | 20 | //String s = list.get(0); 21 | 22 | System.out.println(v); 23 | } 24 | 25 | @Test 26 | public void test2() { 27 | // Calendar c = Calendar.getInstance(); 28 | // Date time = c.getTime(); 29 | // System.out.println(time); 30 | // int i = c.get(Calendar.DAY_OF_YEAR); 31 | // System.out.println(i); 32 | // c.add(Calendar.DAY_OF_YEAR, 1); 33 | // Date time1 = c.getTime(); 34 | // System.out.println(time1); 35 | // System.out.println(c.get(Calendar.DAY_OF_YEAR)); 36 | // for (int j = 0; j < 100; j++) { 37 | // System.out.println(j + ":" + (j % 15)); 38 | // } 39 | 40 | 41 | //获取Calendar对象 42 | Calendar start = Calendar.getInstance(); 43 | // Calendar today = Calendar.getInstance(); 44 | start.set(2020, Calendar.JANUARY, 1); 45 | System.out.println(start.getTime()); 46 | // long day = (today.getTimeInMillis() - start.getTimeInMillis()) / (24 * 60 * 60 * 1000); 47 | // System.out.println(day); 48 | 49 | //获取Calendar对象 50 | // Calendar calendar = Calendar.getInstance(); 51 | //获取今天在一年中的数字 52 | // int days = calendar.get(Calendar.DAY_OF_YEAR); 53 | // System.out.println(days); 54 | // System.out.println("-===-"); 55 | // System.out.println(7 % 11); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/resources/static/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 - Not Found! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

404 - Not Found!

18 |

The requested URL was not found on this server.

19 |
Please check the URL or contact the webmaster.
20 |
21 |

Powered By Noisky 22 |

23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/static/error/405.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 405 - Method Not Allowed! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

405 - Method Not Allowed!

18 |

The method used is not permitted.

19 |
Please contact the webmaster with any queries.
20 |
21 |

Powered By Noisky 22 |

23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/static/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 500 - Internal Server Error! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

500 - Internal Server Error!

18 |

The requested URL caused an internal server error.

19 |
If you get this message repeatedly please contact the webmaster.
20 |
21 |

Powered By Noisky 22 |

23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/static/error/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 - Forbidden! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

403 - Forbidden!

18 |

The requested resources is not available to you

19 |

Maybe you needs a password to access this page.

20 |
Sensitive data is not available for everyone :)
21 |
22 |

Powered By Noisky 23 |

24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/static/error/400.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 400 - Bad Request! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

400 - Bad Request!

18 |

The requested resources is not available to you

19 |

Maybe you needs a password to access this page.

20 |
Please contact the webmaster with any queries. :)
21 |
22 |

Powered By Noisky 23 |

24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/static/error/401.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 401 - Unauthorized! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

401 - Unauthorized!

18 |

The requested resources is not available to you

19 |

Maybe you needs a password to access this page.

20 |
Please contact the webmaster with any queries. :)
21 |
22 |

Powered By Noisky 23 |

24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/static/error/502.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 502 - Bad Gateway! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

502 - Bad Gateway!

18 |

The Service is not available at the moment due to a temporary overloading or maintenance of the 19 | server.

20 |

Please try again later.

21 |
Please contact the webmaster with any queries.
22 |
23 |

Powered By Noisky 24 |

25 | 26 | -------------------------------------------------------------------------------- /src/main/resources/static/error/503.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 503 - Service Unavailable! 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Server Error

16 |
17 |

503 - Service Unavailable!

18 |

The Service is not available at the moment due to a temporary overloading or maintenance of the 19 | server.

20 |

Please try again later.

21 |
Please contact the webmaster with any queries.
22 |
23 |

Powered By Noisky 24 |

25 | 26 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/service/ImageService.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.service; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import me.ffis.randomImage.config.ReadListConfig; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.util.Calendar; 8 | import java.util.List; 9 | 10 | /** 11 | * 随机图片服务类 12 | * Created by fanfan on 2020/01/06. 13 | */ 14 | 15 | @Slf4j 16 | @Service 17 | public class ImageService { 18 | 19 | //随机获取images集合中的图片地址 20 | public String getRandomImages(String imageFile) { 21 | //屏蔽domains的请求 22 | if ("domains".equals(imageFile)) { 23 | return "404"; 24 | } 25 | //判断集合是否为空 26 | if (ReadListConfig.listMap.isEmpty()) { 27 | log.error("listMap集合为空,请检查列表文件是否存在"); 28 | return null; 29 | } else { 30 | //根据传入的参数images获取对应的集合 31 | List images = ReadListConfig.listMap.get(imageFile + ".txt"); 32 | if (images == null) { 33 | return "404"; 34 | } 35 | //根据images集合大小生成随机数 36 | int index = (int) (Math.random() * images.size()); 37 | //获取随机的图片地址 38 | return images.get(index); 39 | } 40 | } 41 | 42 | //获取今日图片 43 | public String getImageByDate(String imageFile) { 44 | //屏蔽domains的请求 45 | if ("domains".equals(imageFile)) { 46 | return "404"; 47 | } 48 | //判断集合是否为空 49 | if (ReadListConfig.listMap.isEmpty()) { 50 | log.error("listMap集合为空,请检查列表文件是否存在"); 51 | return null; 52 | } else { 53 | //根据传入的参数images获取对应的集合 54 | List images = ReadListConfig.listMap.get(imageFile + ".txt"); 55 | if (images == null) { 56 | return "404"; 57 | } 58 | //获取Calendar对象,并设置为2020年1月1日 59 | Calendar begin = Calendar.getInstance(); 60 | begin.set(2020, Calendar.JANUARY, 1); 61 | //获取Calendar对象,计算今天日期到2020年1月1日之间相差多少天 62 | Calendar today = Calendar.getInstance(); 63 | int day = (int) (today.getTimeInMillis() - begin.getTimeInMillis()) / (24 * 60 * 60 * 1000); 64 | //根据今天的日期获取今日图片 65 | int index = (day % images.size()); 66 | //获取今日随机的图片地址 67 | return images.get(index); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.ffis 8 | Random-Image-Api 9 | 1.0.2 10 | jar 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 2.2.2.RELEASE 16 | 17 | 18 | 19 | 1.8 20 | UTF-8 21 | UTF-8 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-logging 40 | 41 | 42 | 43 | org.projectlombok 44 | lombok 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | me.ffis.randomImage.RandomImageApplication 57 | ZIP 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/config/ReadListConfig.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.config; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.stereotype.Component; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.File; 8 | import java.io.FileReader; 9 | import java.io.IOException; 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * 用于读取图片列表和域名白名单数据 17 | * Created by fanfan on 2020/01/05. 18 | */ 19 | 20 | @Slf4j 21 | @Component 22 | public class ReadListConfig { 23 | //创建全局静态成员变量listMap用于保存列表数据 24 | public static Map> listMap = new HashMap<>(); 25 | 26 | static { 27 | //程序启动的时候先加载list文件夹中的文件内容列表到集合中 28 | loadList(); 29 | } 30 | //加载list文件夹下的文件列表到list集合中 31 | public static Boolean loadList() { 32 | //清空集合 33 | listMap.clear(); 34 | //创建list文件夹的文件对象 35 | File file = new File("list"); 36 | if (!file.exists()) { 37 | log.error("list文件夹不存在!"); 38 | return false; 39 | } 40 | //获取list文件夹下的文件列表 41 | String[] list = file.list(); 42 | assert list != null; 43 | if (list.length == 0) { 44 | log.error("list文件夹为空!"); 45 | return false; 46 | } 47 | for (String listFile : list) { 48 | //遍历集合,将.txt结尾的文件内容存到集合中 49 | if (listFile.endsWith(".txt")) { 50 | List arrList = loadFileToList(listFile); 51 | listMap.put(listFile, arrList); 52 | } 53 | } 54 | return true; 55 | } 56 | 57 | //读取list文件夹下指定文件的内容到map集合中 58 | private static List loadFileToList(String listFileName) { 59 | List listFile = new ArrayList<>(); 60 | BufferedReader bw = null; 61 | try { 62 | bw = new BufferedReader(new FileReader("list/" + listFileName)); 63 | String line; 64 | while ((line = bw.readLine())!= null) { 65 | listFile.add(line); 66 | } 67 | } catch (IOException e) { 68 | log.error("列表文件 " + listFileName + " 加载失败!文件不存在!", e); 69 | return null; 70 | } finally { 71 | try { 72 | if (bw != null) 73 | bw.close(); 74 | } catch (IOException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | log.info("列表文件 " + listFileName + " 加载成功!"); 79 | return listFile; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 饭饭's 随机图片API 14 | 16 | 19 | 20 | 21 |
22 |
23 |
饭饭's 随机图片API
24 |
25 |

介绍

26 |
    27 |
  • 饭饭's 随机图片API,是一个外链形式的壁纸服务,通过固定一个 URL 随机输出图片,每次刷新都会输出不一样的图片!
  • 28 |
  • 随机提供 1920*1080 与 2560*1440 分辨率的动漫二次元风格壁纸
  • 29 |
30 |

调用

31 |
    32 |
  • 目前本 API 需要申请才可调用,现在暂时不对外开放。
  • 33 |
34 |
35 |
36 |

37 |

Copyright © 38 | 39 | Designed By Noisky

40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/me/ffis/randomImage/controller/ImageController.java: -------------------------------------------------------------------------------- 1 | package me.ffis.randomImage.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import me.ffis.randomImage.config.ReadListConfig; 5 | import me.ffis.randomImage.pojo.reponse.ReponseCode; 6 | import me.ffis.randomImage.pojo.reponse.Result; 7 | import me.ffis.randomImage.pojo.reponse.ResultResponse; 8 | import me.ffis.randomImage.service.ImageService; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.CrossOrigin; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.ResponseBody; 15 | 16 | import javax.servlet.http.HttpServletResponse; 17 | import java.io.IOException; 18 | 19 | /** 20 | * Created by fanfan on 2020/01/05. 21 | */ 22 | 23 | @Slf4j 24 | @Controller 25 | //开启跨域 26 | @CrossOrigin(allowCredentials = "true", maxAge = 3600) 27 | public class ImageController { 28 | 29 | @Autowired 30 | private ImageService imageService; 31 | 32 | /** 33 | * 随机获取指定图片列表文件中的图片 34 | * 35 | * @param imageFile 图片列表文件名 36 | * @param response response对象 37 | * @return 随机获取到的图片 38 | */ 39 | @ResponseBody 40 | @GetMapping("random/{imageFile}") 41 | public Result getRandomImages(@PathVariable String imageFile, HttpServletResponse response) { 42 | //调用imageService获取随机图片地址 43 | String imgUrl = imageService.getRandomImages(imageFile); 44 | try { 45 | if ("404".equals(imgUrl)) { 46 | response.sendError(404); 47 | return new ResultResponse(ReponseCode.FAIL); 48 | } 49 | if (imgUrl != null) { 50 | //重定向到图片地址 51 | response.sendRedirect(imgUrl); 52 | return new ResultResponse(ReponseCode.SUCCESS); 53 | } 54 | } catch (IOException e) { 55 | log.error("重定向到随机图片地址失败!", e); 56 | } 57 | return new ResultResponse(ReponseCode.FAIL); 58 | } 59 | 60 | /** 61 | * 获取每日图片,即一天换一张 62 | * 63 | * @param imageFile 图片列表文件名 64 | * @param response response对象 65 | * @return 今日图片地址 66 | */ 67 | @ResponseBody 68 | @GetMapping("today/{imageFile}") 69 | public Result getImageByDay(@PathVariable String imageFile, HttpServletResponse response) { 70 | //调用imageService获取随机图片地址 71 | String imgUrl = imageService.getImageByDate(imageFile); 72 | try { 73 | if ("404".equals(imgUrl)) { 74 | response.sendError(404); 75 | return new ResultResponse(ReponseCode.FAIL); 76 | } 77 | if (imgUrl != null) { 78 | //重定向到图片地址 79 | response.sendRedirect(imgUrl); 80 | return new ResultResponse(ReponseCode.SUCCESS); 81 | } 82 | } catch (IOException e) { 83 | log.error("重定向到随机图片地址失败!", e); 84 | } 85 | return new ResultResponse(ReponseCode.FAIL); 86 | } 87 | 88 | /** 89 | * 刷新图片缓存 90 | * 91 | * @return 刷新结果 92 | */ 93 | @ResponseBody 94 | @GetMapping("flush") 95 | public Result flushCache() { 96 | log.info("刷新文件列表的缓存"); 97 | Boolean flag = ReadListConfig.loadList(); 98 | if (!flag) { 99 | return new ResultResponse(ReponseCode.FLUSH_FAIL); 100 | } 101 | return new ResultResponse(ReponseCode.FLUSH_SUCCESS); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) - %cyan(%msg) with PID:${PID:-}%n 21 | UTF-8 22 | 23 | 27 | 28 | 29 | 30 | 31 | 35 | ${LOG_HOME}/${LOG_APPNAME}.log 36 | 37 | 38 | ${LOG_HOME}/${LOG_APPNAME}.%d{yyyy-MM-dd}.log 39 | 40 | 60 41 | 42 | 500MB 43 | 44 | 45 | 46 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} %line - %msg with PID:${PID:-}%n 47 | UTF-8 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 0 79 | 80 | 512 81 | 82 | 83 | 84 | 85 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------