├── README.md ├── ShortUrl.iml ├── pom.xml ├── short_url.sql └── src ├── main ├── java │ └── com │ │ └── rawchen │ │ └── shorturl │ │ ├── DTO │ │ └── ShortUrlDTO.java │ │ ├── ShortUrlApplication.java │ │ ├── controller │ │ ├── ApiController.java │ │ └── WebController.java │ │ ├── entity │ │ ├── Log.java │ │ ├── Result.java │ │ ├── SevenDayLog.java │ │ └── ShortUrl.java │ │ ├── execution │ │ └── ScheduleTask.java │ │ ├── filter │ │ └── CorsFilter.java │ │ ├── limit │ │ ├── RateLimit.java │ │ ├── RateLimitAspect.java │ │ └── RateLimitUtil.java │ │ ├── mapper │ │ ├── LogMapper.java │ │ └── UrlMapper.java │ │ └── util │ │ ├── LogUtil.java │ │ └── StringUtil.java └── resources │ ├── application.yml │ ├── mapper │ ├── LogMapper.xml │ └── UrlMapper.xml │ ├── static │ ├── bootstrap-3.3.7 │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap-theme.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ ├── css │ │ ├── error.css │ │ └── style.css │ ├── datepicker │ │ ├── datepicker.min.css │ │ └── datepicker.min.js │ ├── img │ │ ├── banner.png │ │ ├── bg.png │ │ ├── favicon.ico │ │ └── logo.png │ ├── js │ │ ├── application.fn.js │ │ ├── application.js │ │ ├── clipboard.min.js │ │ └── jquery.min.js │ └── layer │ │ ├── layer.js │ │ ├── mobile │ │ ├── layer.js │ │ └── need │ │ │ └── layer.css │ │ └── theme │ │ └── default │ │ ├── icon-ext.png │ │ ├── icon.png │ │ ├── layer.css │ │ ├── loading-0.gif │ │ ├── loading-1.gif │ │ └── loading-2.gif │ └── templates │ ├── 400.html │ ├── 404.html │ ├── error │ ├── 404.html │ └── 500.html │ ├── index.html │ └── password.html └── test └── java └── com └── rawchen └── shorturl └── ShortUrlApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | # 短链生成服务 - ShortUrl 2 | 3 | ## 服务在线使用及开发环境 4 | 5 | > https://ivii.cn 6 | > 7 | > JDK 8 + MySQL 5.7 + IDEA 2021 8 | 9 | ## 使用 10 | 11 | * 确保java8及以上环境,在[releases](https://github.com/rawchen/ShortUrl/releases)页面下载jar运行程序。 12 | * 通过`java -jar ShortUrl.jar`运行该程序,默认访问地址:[http://localhost:8989](http://localhost:8989)。 13 | * 需部署MySQL数据库,帐号root密码root,端口3306。新建名为`short_url`的库,导入`short_url.sql` 14 | * Linux部署使用如下命令: 15 | ```bash 16 | nohup java -jar -Xmx200m ShortUrl.jar >> ShortUrl.log & 17 | ``` 18 | 19 | ## 开发 20 | 21 | * 确保java8及Maven环境,下载项目后通过IDEA打开项目也可直接修改相关文本。 22 | * 可配置application.yml中的端口号,数据库连接信息等,通过IDEA运行这个Spring Boot项目。 23 | * 不想使用IDEA也可文本编辑后Maven打包成jar运行,打包命令`mvn clean package`。 24 | 25 | 26 | ## 功能 27 | 28 | - [x] 有效期 29 | - [x] 访问密码 30 | - [x] 随机短链 31 | - [x] 生成二维码 32 | - [x] 接口限流 33 | 34 | ## 案例截图 35 | 36 | > https://ivii.cn -------------------------------------------------------------------------------- /ShortUrl.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 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 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.5 9 | 10 | 11 | com.rawchen 12 | ShortUrl 13 | 0.0.1-SNAPSHOT 14 | ShortUrl 15 | ShortUrl 16 | 17 | 1.8 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-thymeleaf 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-devtools 32 | runtime 33 | true 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | 42 | com.alibaba 43 | druid-spring-boot-starter 44 | 1.1.13 45 | 46 | 47 | 48 | org.mybatis.spring.boot 49 | mybatis-spring-boot-starter 50 | 1.3.3 51 | 52 | 53 | 54 | mysql 55 | mysql-connector-java 56 | 57 | 58 | 59 | com.alibaba 60 | fastjson 61 | 1.2.61 62 | 63 | 64 | 65 | cn.hutool 66 | hutool-all 67 | 5.1.3 68 | 69 | 70 | 71 | commons-httpclient 72 | commons-httpclient 73 | 3.1 74 | 75 | 76 | 77 | com.google.guava 78 | guava 79 | 29.0-jre 80 | 81 | 82 | 83 | 84 | eu.bitwalker 85 | UserAgentUtils 86 | 1.21 87 | 88 | 89 | 90 | org.springframework.boot 91 | spring-boot-starter-aop 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.springframework.boot 100 | spring-boot-maven-plugin 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /short_url.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : short_url 5 | Source Server Type : MySQL 6 | Source Server Version : 50734 7 | Source Schema : short_url 8 | 9 | Target Server Type : MySQL 10 | Target Server Version : 50734 11 | File Encoding : 65001 12 | 13 | Date: 13/09/2022 00:08:25 14 | */ 15 | 16 | SET NAMES utf8mb4; 17 | SET FOREIGN_KEY_CHECKS = 0; 18 | 19 | -- ---------------------------- 20 | -- Table structure for log 21 | -- ---------------------------- 22 | DROP TABLE IF EXISTS `log`; 23 | CREATE TABLE `log` ( 24 | `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', 25 | `ua` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT 'UserAgent', 26 | `browser_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '浏览器名', 27 | `os_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作系统名', 28 | `api_path` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '访问api路径', 29 | `ip` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'ip地址', 30 | `referer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来源地址', 31 | `access_time` datetime(0) NULL DEFAULT NULL COMMENT '访问时间', 32 | `short_url_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '短链id', 33 | PRIMARY KEY (`id`) USING BTREE, 34 | INDEX `idx_short_url_id`(`short_url_id`) USING BTREE 35 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT; 36 | 37 | -- ---------------------------- 38 | -- Table structure for short_url 39 | -- ---------------------------- 40 | DROP TABLE IF EXISTS `short_url`; 41 | CREATE TABLE `short_url` ( 42 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 43 | `code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 44 | `link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL, 45 | `effective_date` date NULL DEFAULT NULL, 46 | `password` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 47 | `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, 48 | `save_time` datetime(0) NULL DEFAULT NULL, 49 | `view_number` bigint(20) NULL DEFAULT 0, 50 | PRIMARY KEY (`id`) USING BTREE, 51 | UNIQUE INDEX `code`(`code`) USING BTREE 52 | ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; 53 | 54 | SET FOREIGN_KEY_CHECKS = 1; 55 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/DTO/ShortUrlDTO.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.DTO; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | 5 | import java.util.Date; 6 | 7 | /** 8 | * @author RawChen 9 | * @date 2022-07-23 02:28 10 | */ 11 | public class ShortUrlDTO { 12 | 13 | private String longUrl; 14 | 15 | @JsonFormat(pattern = "yyyy/MM/dd") 16 | private Date effectiveDate; 17 | 18 | private String password; 19 | 20 | public ShortUrlDTO() { 21 | } 22 | 23 | public ShortUrlDTO(String longUrl, Date effectiveDate, String password) { 24 | this.longUrl = longUrl; 25 | this.effectiveDate = effectiveDate; 26 | this.password = password; 27 | } 28 | 29 | public String getLongUrl() { 30 | return longUrl; 31 | } 32 | 33 | public void setLongUrl(String longUrl) { 34 | this.longUrl = longUrl; 35 | } 36 | 37 | public Date getEffectiveDate() { 38 | return effectiveDate; 39 | } 40 | 41 | public void setEffectiveDate(Date effectiveDate) { 42 | this.effectiveDate = effectiveDate; 43 | } 44 | 45 | public String getPassword() { 46 | return password; 47 | } 48 | 49 | public void setPassword(String password) { 50 | this.password = password; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return "ShortUrlDTO{" + 56 | "longUrl='" + longUrl + '\'' + 57 | ", effectiveDate=" + effectiveDate + 58 | ", password='" + password + '\'' + 59 | '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/ShortUrlApplication.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ShortUrlApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ShortUrlApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/controller/ApiController.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.controller; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.rawchen.shorturl.DTO.ShortUrlDTO; 5 | import com.rawchen.shorturl.entity.Result; 6 | import com.rawchen.shorturl.entity.ShortUrl; 7 | import com.rawchen.shorturl.limit.RateLimit; 8 | import com.rawchen.shorturl.mapper.UrlMapper; 9 | import com.rawchen.shorturl.util.StringUtil; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.ResponseBody; 15 | 16 | import javax.servlet.http.HttpServletRequest; 17 | 18 | /** 19 | * @author RawChen 20 | * @date 2022-03-30 17:49 21 | */ 22 | @Controller 23 | public class ApiController { 24 | 25 | @Autowired 26 | private UrlMapper mapper; 27 | 28 | @RateLimit(name = "新增短链接口", perSecond = 0.1) //默认1秒进0.1个令牌 29 | @PostMapping("/insert") 30 | @ResponseBody 31 | public Result insert(HttpServletRequest request, @RequestBody ShortUrlDTO dto) { 32 | try { 33 | if (dto == null) 34 | return Result.fail("请勿直接访问"); 35 | if (StrUtil.isBlank(dto.getLongUrl())) 36 | return Result.fail("请填写URL链接"); 37 | 38 | String tempUrl = dto.getLongUrl().trim(); 39 | String password = ""; 40 | 41 | if (!StringUtil.isUrl(tempUrl)) { 42 | return Result.fail("请正确填写URL链接"); 43 | } 44 | 45 | if (StrUtil.isBlank(dto.getPassword())) { 46 | dto.setPassword(null); 47 | } else { 48 | password = dto.getPassword().trim(); 49 | } 50 | 51 | //如果有填写过期时间,则重新生成新的不重复短链 52 | if (dto.getEffectiveDate() != null || !StrUtil.isBlank(password)) { 53 | String code = StringUtil.getRandomStrNoCapitalLetter(5); 54 | //数据库不存在给定的link的短链接,先检查下生成的编码是否有重复 55 | while (mapper.getByCode(code) != null) { 56 | //有重复重新生成编码 57 | code = StringUtil.getRandomStrNoCapitalLetter(5); 58 | } 59 | mapper.insert(new ShortUrl(code, tempUrl, 60 | dto.getEffectiveDate(), dto.getPassword(), 61 | StringUtil.getIpAddr(request))); 62 | return Result.ok(code); 63 | } 64 | 65 | //没填过期日期,一般短链,如果重复就使用数据库的 66 | ShortUrl shortUrl = mapper.getByLink(tempUrl); 67 | if (shortUrl != null) { 68 | //数据库已经存在相同link的短链接 69 | return Result.ok(shortUrl.getCode()); 70 | } else { 71 | String code = StringUtil.getRandomStrNoCapitalLetter(5); 72 | //数据库不存在给定的link的短链接,先检查下生成的编码是否有重复 73 | while (mapper.getByCode(code) != null) { 74 | //有重复重新生成编码 75 | code = StringUtil.getRandomStrNoCapitalLetter(5); 76 | } 77 | mapper.insert(new ShortUrl(code, tempUrl, StringUtil.getIpAddr(request))); 78 | return Result.ok(code); 79 | } 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | return Result.error(e.getMessage()); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/controller/WebController.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.controller; 2 | 3 | import cn.hutool.core.util.StrUtil; 4 | import com.rawchen.shorturl.entity.Result; 5 | import com.rawchen.shorturl.entity.ShortUrl; 6 | import com.rawchen.shorturl.limit.RateLimit; 7 | import com.rawchen.shorturl.mapper.LogMapper; 8 | import com.rawchen.shorturl.mapper.UrlMapper; 9 | import com.rawchen.shorturl.util.LogUtil; 10 | import org.apache.commons.httpclient.util.URIUtil; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Controller; 13 | import org.springframework.ui.Model; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.RequestBody; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.ResponseBody; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | 21 | /** 22 | * @author RawChen 23 | * @date 2022-03-30 17:49 24 | */ 25 | @Controller 26 | public class WebController { 27 | 28 | @Autowired 29 | private UrlMapper mapper; 30 | 31 | @Autowired 32 | private LogMapper logMapper; 33 | 34 | @RequestMapping("/") 35 | public String index() { 36 | return "index"; 37 | } 38 | 39 | @RequestMapping("/404") 40 | public String errorIndex() { 41 | return "404"; 42 | } 43 | 44 | @RequestMapping("/400") 45 | public String limitPage() { 46 | return "400"; 47 | } 48 | 49 | @RateLimit(name = "短链跳转接口", perSecond = 0.5) 50 | @RequestMapping("/{code}") 51 | public String toLink(HttpServletRequest request, @PathVariable String code, Model model) { 52 | try { 53 | ShortUrl shortUrl = mapper.getByCode(code); 54 | 55 | if (shortUrl != null) { 56 | //如果有密码 57 | if (shortUrl.getPassword() != null) { 58 | shortUrl.setPassword(shortUrl.getPassword().trim()); 59 | } 60 | //没密码 61 | if (StrUtil.isBlank(shortUrl.getPassword())) { 62 | //增加访问数 63 | mapper.addViewNumberById(shortUrl.getId()); 64 | //插入日志 65 | logMapper.insert(LogUtil.getLog(request, shortUrl.getLink(), shortUrl.getId())); 66 | return "redirect:" + URIUtil.encodeQuery(shortUrl.getLink()); 67 | } else { 68 | model.addAttribute("code", shortUrl.getCode()); 69 | return "password"; 70 | } 71 | } else { 72 | return "redirect:" + "/404"; 73 | } 74 | } catch (Exception e) { 75 | e.printStackTrace(); 76 | } 77 | return "redirect:" + "/404"; 78 | } 79 | 80 | @ResponseBody 81 | @RateLimit(name = "短链带密码跳转接口", perSecond = 0.5) 82 | @RequestMapping("/pageByPassword") 83 | public Result pageByPassword(HttpServletRequest request, @RequestBody ShortUrl shortUrlData) { 84 | try { 85 | if (shortUrlData != null && StrUtil.isBlank(shortUrlData.getPassword())) { 86 | return Result.fail("需要密码哦"); 87 | } else { 88 | if (shortUrlData != null && shortUrlData.getPassword() != null) { 89 | ShortUrl shortUrl = mapper.getByCodeAndPassword(shortUrlData); 90 | if (shortUrl != null) { 91 | //增加访问数 92 | mapper.addViewNumberById(shortUrl.getId()); 93 | //插入日志 94 | logMapper.insert(LogUtil.getLog(request, URIUtil.encodeQuery(shortUrl.getLink()), shortUrl.getId())); 95 | return Result.ok(URIUtil.encodeQuery(shortUrl.getLink())); 96 | } else { 97 | return Result.fail("密码错误"); 98 | } 99 | } 100 | } 101 | } catch (Exception e) { 102 | e.printStackTrace(); 103 | } 104 | return Result.error("系统错误"); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/entity/Log.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import org.springframework.format.annotation.DateTimeFormat; 5 | 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | 9 | public class Log implements Serializable { 10 | 11 | private Long id; 12 | 13 | private String browserName; 14 | 15 | private String osName; 16 | 17 | private String apiPath; 18 | 19 | private String ip; 20 | 21 | private String referer; 22 | 23 | @DateTimeFormat(pattern = "yyyy-MM-dd") 24 | @JsonFormat(pattern = "yyyy-MM-dd") 25 | private Date accessTime; 26 | 27 | private Long shortUrlId; 28 | 29 | private String ua; 30 | 31 | private static final long serialVersionUID = 1L; 32 | 33 | public Long getId() { 34 | return id; 35 | } 36 | 37 | public void setId(Long id) { 38 | this.id = id; 39 | } 40 | 41 | public String getBrowserName() { 42 | return browserName; 43 | } 44 | 45 | public void setBrowserName(String browserName) { 46 | this.browserName = browserName == null ? null : browserName.trim(); 47 | } 48 | 49 | public String getOsName() { 50 | return osName; 51 | } 52 | 53 | public void setOsName(String osName) { 54 | this.osName = osName == null ? null : osName.trim(); 55 | } 56 | 57 | public String getApiPath() { 58 | return apiPath; 59 | } 60 | 61 | public void setApiPath(String apiPath) { 62 | this.apiPath = apiPath == null ? null : apiPath.trim(); 63 | } 64 | 65 | public String getIp() { 66 | return ip; 67 | } 68 | 69 | public void setIp(String ip) { 70 | this.ip = ip == null ? null : ip.trim(); 71 | } 72 | 73 | public String getReferer() { 74 | return referer; 75 | } 76 | 77 | public void setReferer(String referer) { 78 | this.referer = referer == null ? null : referer.trim(); 79 | } 80 | 81 | public Date getAccessTime() { 82 | return accessTime; 83 | } 84 | 85 | public void setAccessTime(Date accessTime) { 86 | this.accessTime = accessTime; 87 | } 88 | 89 | public Long getShortUrlId() { 90 | return shortUrlId; 91 | } 92 | 93 | public void setShortUrlId(Long shortUrlId) { 94 | this.shortUrlId = shortUrlId; 95 | } 96 | 97 | public String getUa() { 98 | return ua; 99 | } 100 | 101 | public void setUa(String ua) { 102 | this.ua = ua == null ? null : ua.trim(); 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return "Log{" + 108 | "id=" + id + 109 | ", browserName='" + browserName + '\'' + 110 | ", osName='" + osName + '\'' + 111 | ", apiPath='" + apiPath + '\'' + 112 | ", ip='" + ip + '\'' + 113 | ", referer='" + referer + '\'' + 114 | ", accessTime=" + accessTime + 115 | ", shortUrlId=" + shortUrlId + 116 | ", ua='" + ua + '\'' + 117 | '}'; 118 | } 119 | } -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/entity/Result.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.entity; 2 | 3 | /** 4 | * 封装结果 5 | * 6 | * @author RawChen 7 | * @date 2022-03-30 17:49 8 | */ 9 | public class Result { 10 | private Integer code; 11 | private String msg; 12 | private Object data; 13 | 14 | public Result() { 15 | } 16 | 17 | private Result(Integer code, String msg) { 18 | this.code = code; 19 | this.msg = msg; 20 | this.data = null; 21 | } 22 | 23 | private Result(Integer code, String msg, Object data) { 24 | this.code = code; 25 | this.msg = msg; 26 | this.data = data; 27 | } 28 | 29 | public static Result ok(String msg, Object data) { 30 | return new Result(200, msg, data); 31 | } 32 | 33 | public static Result ok(String msg) { 34 | return new Result(200, msg); 35 | } 36 | 37 | public static Result ok() { 38 | return new Result(200, "success"); 39 | } 40 | 41 | public static Result ok(Object data) { 42 | return new Result(200, "success", data); 43 | } 44 | 45 | public static Result fail(String msg) { 46 | return new Result(400, msg); 47 | } 48 | 49 | public static Result fail() { 50 | return new Result(400, "fail"); 51 | } 52 | 53 | public static Result error(String msg) { 54 | return new Result(500, msg); 55 | } 56 | 57 | public static Result error() { 58 | return new Result(500, "error"); 59 | } 60 | 61 | public static Result create(Integer code, String msg, Object data) { 62 | return new Result(code, msg, data); 63 | } 64 | 65 | public static Result create(Integer code, String msg) { 66 | return new Result(code, msg); 67 | } 68 | 69 | public Integer getCode() { 70 | return code; 71 | } 72 | 73 | public void setCode(Integer code) { 74 | this.code = code; 75 | } 76 | 77 | public String getMsg() { 78 | return msg; 79 | } 80 | 81 | public void setMsg(String msg) { 82 | this.msg = msg; 83 | } 84 | 85 | public Object getData() { 86 | return data; 87 | } 88 | 89 | public void setData(Object data) { 90 | this.data = data; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "Result{" + 96 | "code=" + code + 97 | ", msg='" + msg + '\'' + 98 | ", data=" + data + 99 | '}'; 100 | } 101 | } -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/entity/SevenDayLog.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import org.springframework.format.annotation.DateTimeFormat; 5 | 6 | import java.io.Serializable; 7 | import java.util.Date; 8 | 9 | /** 10 | * @author RawChen 11 | * @since 2021-10-22 13:47 12 | */ 13 | public class SevenDayLog implements Serializable { 14 | 15 | @DateTimeFormat(pattern = "yyyy-MM-dd") 16 | @JsonFormat(pattern = "yyyy-MM-dd") 17 | private Date accessDate; 18 | 19 | private Integer accessValue; 20 | 21 | public Date getAccessDate() { 22 | return accessDate; 23 | } 24 | 25 | public void setAccessDate(Date accessDate) { 26 | this.accessDate = accessDate; 27 | } 28 | 29 | public Integer getAccessValue() { 30 | return accessValue; 31 | } 32 | 33 | public void setAccessValue(Integer accessValue) { 34 | this.accessValue = accessValue; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "SevenDayLog{" + 40 | "accessDate=" + accessDate + 41 | ", accessValue=" + accessValue + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/entity/ShortUrl.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import org.springframework.format.annotation.DateTimeFormat; 5 | 6 | import java.util.Date; 7 | 8 | /** 9 | * @author RawChen 10 | * @date 2022-03-30 22:01 11 | */ 12 | public class ShortUrl { 13 | 14 | private Long id; 15 | 16 | private String code; 17 | 18 | private String link; 19 | 20 | @DateTimeFormat(pattern = "yyyy-MM-dd") 21 | @JsonFormat(pattern = "yyyy-MM-dd") 22 | private Date effectiveDate; 23 | 24 | private String password; 25 | 26 | private String ip; 27 | 28 | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 29 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 30 | private Date saveTime; 31 | 32 | private Long viewNumber; 33 | 34 | public ShortUrl() { 35 | } 36 | 37 | public ShortUrl(String code, String link, String ip) { 38 | this.code = code; 39 | this.link = link; 40 | this.ip = ip; 41 | this.saveTime = new Date(); 42 | } 43 | 44 | public ShortUrl(String code, String link, Date effectiveDate, String password) { 45 | this.code = code; 46 | this.link = link; 47 | this.effectiveDate = effectiveDate; 48 | this.password = password; 49 | } 50 | 51 | public ShortUrl(String code, String link, Date effectiveDate, String password, String ip) { 52 | this.code = code; 53 | this.link = link; 54 | this.effectiveDate = effectiveDate; 55 | this.password = password; 56 | this.ip = ip; 57 | this.saveTime = new Date(); 58 | } 59 | 60 | 61 | public String getIp() { 62 | return ip; 63 | } 64 | 65 | public void setIp(String ip) { 66 | this.ip = ip; 67 | } 68 | 69 | public Date getSaveTime() { 70 | return saveTime; 71 | } 72 | 73 | public void setSaveTime(Date saveTime) { 74 | this.saveTime = saveTime; 75 | } 76 | 77 | public Long getViewNumber() { 78 | return viewNumber; 79 | } 80 | 81 | public void setViewNumber(Long viewNumber) { 82 | this.viewNumber = viewNumber; 83 | } 84 | 85 | public Long getId() { 86 | return id; 87 | } 88 | 89 | public void setId(Long id) { 90 | this.id = id; 91 | } 92 | 93 | public String getCode() { 94 | return code; 95 | } 96 | 97 | public void setCode(String code) { 98 | this.code = code; 99 | } 100 | 101 | public String getLink() { 102 | return link; 103 | } 104 | 105 | public void setLink(String link) { 106 | this.link = link; 107 | } 108 | 109 | public Date getEffectiveDate() { 110 | return effectiveDate; 111 | } 112 | 113 | public void setEffectiveDate(Date effectiveDate) { 114 | this.effectiveDate = effectiveDate; 115 | } 116 | 117 | public String getPassword() { 118 | return password; 119 | } 120 | 121 | public void setPassword(String password) { 122 | this.password = password; 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return "ShortUrl{" + 128 | "id=" + id + 129 | ", code='" + code + '\'' + 130 | ", link='" + link + '\'' + 131 | ", effectiveDate=" + effectiveDate + 132 | ", password='" + password + '\'' + 133 | ", ip='" + ip + '\'' + 134 | ", saveTime=" + saveTime + 135 | ", viewNumber=" + viewNumber + 136 | '}'; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/execution/ScheduleTask.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.execution; 2 | 3 | import com.rawchen.shorturl.mapper.UrlMapper; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | import org.springframework.scheduling.annotation.Scheduled; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * Spring Boot定时任务 11 | * 12 | * @author RawChen 13 | * @date 2022-07-23 01:45 14 | */ 15 | @Component 16 | @EnableScheduling 17 | public class ScheduleTask { 18 | 19 | @Autowired 20 | private UrlMapper mapper; 21 | 22 | /** 23 | * 每天1点执行扫描删除过期短链 24 | * @throws Exception 25 | */ 26 | @Scheduled(cron = "0 0 1 * * ?") 27 | private void scanDeleteExpiredLink() throws Exception { 28 | mapper.scanDeleteExpiredLink(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/filter/CorsFilter.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.filter; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import javax.servlet.*; 6 | import javax.servlet.annotation.WebFilter; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author RawChen 12 | * @date 2022-07-25 21:47 13 | */ 14 | @Component 15 | @WebFilter 16 | public class CorsFilter implements Filter { 17 | @Override 18 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 19 | HttpServletResponse response = (HttpServletResponse) servletResponse; 20 | response.setHeader("Access-Control-Allow-Origin", "*"); 21 | response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); 22 | response.setHeader("Access-Control-Max-Age", "3600"); 23 | response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); 24 | filterChain.doFilter(servletRequest, servletResponse); 25 | } 26 | 27 | @Override 28 | public void init(FilterConfig filterConfig) throws ServletException { 29 | } 30 | 31 | @Override 32 | public void destroy() { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/limit/RateLimit.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.limit; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 限流注解 10 | * 11 | * @author RawChen 12 | * @date 2022-03-31 11:44 13 | */ 14 | @Target(ElementType.METHOD) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface RateLimit { 17 | 18 | /** 19 | * 资源名称 20 | * 21 | * @return 22 | */ 23 | String name() default "默认资源"; 24 | 25 | /** 26 | * 每秒允许数(qps),默认每秒0.1次也就是10秒允许访问一次 27 | * 28 | * @return 29 | */ 30 | double perSecond() default 0.1; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/limit/RateLimitAspect.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.limit; 2 | 3 | import com.google.common.cache.CacheBuilder; 4 | import com.google.common.cache.CacheLoader; 5 | import com.google.common.cache.LoadingCache; 6 | import com.google.common.util.concurrent.RateLimiter; 7 | import com.rawchen.shorturl.entity.Result; 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | import org.aspectj.lang.annotation.Pointcut; 12 | import org.aspectj.lang.reflect.MethodSignature; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.stereotype.Component; 16 | import org.springframework.web.context.request.RequestContextHolder; 17 | import org.springframework.web.context.request.ServletRequestAttributes; 18 | 19 | import javax.servlet.http.HttpServletRequest; 20 | import java.lang.reflect.Method; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * 限流切面 25 | * 26 | * @author RawChen 27 | * @date 2022-03-31 11:46 28 | */ 29 | @Aspect 30 | @Component 31 | public class RateLimitAspect { 32 | 33 | private static final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class); 34 | 35 | /** 36 | * 缓存 37 | * maximumSize 设置缓存个数 38 | * expireAfterWrite 写入后过期时间 39 | */ 40 | private static LoadingCache limitCaches = CacheBuilder.newBuilder() 41 | .maximumSize(1000) 42 | .expireAfterWrite(1, TimeUnit.DAYS) 43 | .build(new CacheLoader() { 44 | @Override 45 | public RateLimiter load(String key) { 46 | double perSecond = RateLimitUtil.getCacheKeyPerSecond(key); 47 | return RateLimiter.create(perSecond); 48 | } 49 | }); 50 | 51 | /** 52 | * 切点 53 | * 通过扫包切入 @Pointcut("execution(public * com.rawchen.shorturl.*.*(..))") 54 | * 带有指定注解切入 @Pointcut("@annotation(com.rawchen.shorturl.annotation.RateLimit)") 55 | */ 56 | @Pointcut("@annotation(com.rawchen.shorturl.limit.RateLimit)") 57 | public void pointcut() { 58 | } 59 | 60 | @Around("pointcut()") 61 | public Object around(ProceedingJoinPoint point) throws Throwable { 62 | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 63 | MethodSignature signature = (MethodSignature) point.getSignature(); 64 | Method method = signature.getMethod(); 65 | if (method.isAnnotationPresent(RateLimit.class)) { 66 | String cacheKey = RateLimitUtil.generateCacheKey(method, request); 67 | RateLimiter limiter = limitCaches.get(cacheKey); 68 | if (!limiter.tryAcquire()) { 69 | String pointMethodName = point.getSignature().getName(); 70 | logger.info("限流{}方法,具体内容【{}】", pointMethodName, cacheKey); 71 | if ("toLink".equals(pointMethodName)) { 72 | return "redirect:" + "/400"; 73 | } else { 74 | return Result.fail("你手速太快了"); 75 | } 76 | } 77 | } 78 | return point.proceed(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/limit/RateLimitUtil.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.limit; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import java.lang.reflect.Method; 5 | import java.net.InetAddress; 6 | import java.net.UnknownHostException; 7 | 8 | /** 9 | * 限流工具 10 | * 11 | * @author RawChen 12 | * @date 2022-03-31 11:48 13 | */ 14 | public class RateLimitUtil { 15 | /** 16 | * 获取唯一key根据注解类型,规则为: 资源名:ip:perSecond 17 | * 18 | * @param method 19 | * @param request 20 | * @return 21 | */ 22 | public static String generateCacheKey(Method method, HttpServletRequest request) { 23 | //获取方法上的注解 24 | RateLimit rateLimit = method.getAnnotation(RateLimit.class); 25 | StringBuffer cacheKey = new StringBuffer(rateLimit.name() + ":"); 26 | cacheKey.append(getIpAddr(request) + ":"); 27 | cacheKey.append(rateLimit.perSecond()); 28 | return cacheKey.toString(); 29 | } 30 | 31 | /** 32 | * 获取缓存key的限制每秒访问次数 33 | *

34 | * 规则 资源名:业务key:perSecond 35 | * 36 | * @param cacheKey 37 | * @return 38 | */ 39 | public static double getCacheKeyPerSecond(String cacheKey) { 40 | String perSecond = cacheKey.split(":")[2]; 41 | return Double.parseDouble(perSecond); 42 | } 43 | 44 | /** 45 | * 获取客户端IP地址 46 | * 47 | * @param request 请求 48 | * @return 49 | */ 50 | public static String getIpAddr(HttpServletRequest request) { 51 | String ip = request.getHeader("x-forwarded-for"); 52 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 53 | ip = request.getHeader("Proxy-Client-IP"); 54 | } 55 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 56 | ip = request.getHeader("WL-Proxy-Client-IP"); 57 | } 58 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 59 | ip = request.getRemoteAddr(); 60 | if ("127.0.0.1".equals(ip)) { 61 | //根据网卡取本机配置的IP 62 | InetAddress inet = null; 63 | try { 64 | inet = InetAddress.getLocalHost(); 65 | } catch (UnknownHostException e) { 66 | e.printStackTrace(); 67 | } 68 | ip = inet.getHostAddress(); 69 | } 70 | } 71 | // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 72 | if (ip != null && ip.length() > 15) { 73 | if (ip.indexOf(",") > 0) { 74 | ip = ip.substring(0, ip.indexOf(",")); 75 | } 76 | } 77 | if ("0:0:0:0:0:0:0:1".equals(ip)) { 78 | ip = "127.0.0.1"; 79 | } 80 | return ip; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/mapper/LogMapper.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.mapper; 2 | 3 | import com.rawchen.shorturl.entity.Log; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | /** 7 | * Mapper 接口 8 | * 9 | * @author RawChen 10 | * @date 2022-09-12 23:15 11 | */ 12 | @Mapper 13 | public interface LogMapper { 14 | 15 | int insert(Log log); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/mapper/UrlMapper.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.mapper; 2 | 3 | import com.rawchen.shorturl.entity.ShortUrl; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Update; 6 | 7 | /** 8 | * Mapper 接口 9 | * 10 | * @author RawChen 11 | * @date 2022-03-30 17:49 12 | */ 13 | @Mapper 14 | public interface UrlMapper { 15 | 16 | ShortUrl getByLink(String link); 17 | 18 | ShortUrl getByCode(String code); 19 | 20 | void insert(ShortUrl shortUrl); 21 | 22 | void scanDeleteExpiredLink(); 23 | 24 | ShortUrl getByCodeAndPassword(ShortUrl shortUrlData); 25 | 26 | @Update("UPDATE short_url SET `view_number` = (`view_number` + 1) WHERE id = #{id}") 27 | void addViewNumberById(Long id); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.util; 2 | 3 | import com.rawchen.shorturl.entity.Log; 4 | import eu.bitwalker.useragentutils.Browser; 5 | import eu.bitwalker.useragentutils.OperatingSystem; 6 | import eu.bitwalker.useragentutils.UserAgent; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import java.util.Date; 10 | 11 | public class LogUtil { 12 | public static Log getLog(HttpServletRequest request,String apiPath, Long id) { 13 | 14 | UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent")); 15 | Browser browser = userAgent.getBrowser(); 16 | OperatingSystem os = userAgent.getOperatingSystem(); 17 | 18 | Log log = new Log(); 19 | log.setUa(request.getHeader("User-Agent")); 20 | log.setBrowserName(browser.getName()); 21 | log.setOsName(os.getName()); 22 | log.setIp(StringUtil.getIpAddr(request)); 23 | log.setAccessTime(new Date()); 24 | log.setReferer(request.getHeader("Referer")); 25 | log.setApiPath(apiPath); 26 | log.setShortUrlId(id); 27 | return log; 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/rawchen/shorturl/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl.util; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import java.util.Random; 5 | import java.util.regex.Pattern; 6 | 7 | import static cn.hutool.core.util.StrUtil.isBlank; 8 | 9 | /** 10 | * @author RawChen 11 | * @date 2022-03-30 22:38 12 | */ 13 | public class StringUtil { 14 | 15 | static Random random = new Random(); 16 | 17 | /** 18 | * 根据0-9、A-Z、a-z随机组成字符串 19 | * 20 | * @param length 21 | * @return 22 | */ 23 | public static String getRandomStr(int length) { 24 | //1-10 11-36 37-62 25 | //0-9 A-Z a-z 26 | //48-57 65-90 97-122 27 | StringBuilder sb = new StringBuilder(length); 28 | for (int i = 0; i < length; i++) { 29 | //[1, 62] 30 | int ran = random.nextInt(62) + 1; 31 | if (ran > 36) { 32 | sb.append((char) (ran + 60)); 33 | } else if (ran > 10) { 34 | sb.append((char) (ran + 54)); 35 | } else { 36 | sb.append((char) (ran + 47)); 37 | } 38 | } 39 | return sb.toString(); 40 | } 41 | 42 | /** 43 | * 根据0-9、A-Z、a-z随机组成字符串去除相似字符 44 | * 45 | * @param length 46 | * @return 47 | */ 48 | public static String getRandomStrNoSimilar(int length) { 49 | //1-10 11-36 37-62 50 | //0-9 A-Z a-z 51 | //48-57 65-90 97-122 52 | StringBuilder sb = new StringBuilder(length); 53 | for (int i = 0; i < length; i++) { 54 | //[1, 62] 55 | int ran = random.nextInt(62) + 1; 56 | 57 | while ("ilo".contains(String.valueOf((char) (ran + 60))) 58 | || "CIJKLOPSUVWXYZ".contains(String.valueOf((char) (ran + 54))) 59 | || "01".contains(String.valueOf((char) (ran + 47)))) { 60 | 61 | if (ran > 36) { 62 | // a-z 63 | sb.append((char) (ran + 60)); 64 | } else if (ran > 10) { 65 | // A-Z 66 | sb.append((char) (ran + 54)); 67 | } else { 68 | // 0-9 69 | sb.append((char) (ran + 47)); 70 | } 71 | ran = random.nextInt(62) + 1; 72 | } 73 | 74 | if (ran > 36) { 75 | sb.append((char) (ran + 60)); 76 | } else if (ran > 10) { 77 | sb.append((char) (ran + 54)); 78 | } else { 79 | sb.append((char) (ran + 47)); 80 | } 81 | } 82 | return sb.toString(); 83 | } 84 | 85 | /** 86 | * 根据0-9、a-z随机组成字符串并去除相似字符 87 | * 88 | * @param length 89 | * @return 90 | */ 91 | public static String getRandomStrNoCapitalLetter(int length) { 92 | //1-10 11-36 37-62 93 | //0-9 A-Z a-z 94 | //48-57 65-90 97-122 95 | StringBuilder sb = new StringBuilder(length); 96 | for (int i = 0; i < length; i++) { 97 | //[1, 62] 98 | int ran = random.nextInt(62) + 1; 99 | 100 | while ("ilo".contains(String.valueOf((char) (ran + 60))) 101 | || "01".contains(String.valueOf((char) (ran + 47))) 102 | || (ran >= 11 && ran <= 36)) { 103 | ran = random.nextInt(62) + 1; 104 | } 105 | 106 | if (ran > 36) { 107 | sb.append((char) (ran + 60)); 108 | } else { 109 | sb.append((char) (ran + 47)); 110 | } 111 | } 112 | return sb.toString(); 113 | } 114 | 115 | public static boolean isUrl(String str) { 116 | if (str == null || "".equals(str)) { 117 | return false; 118 | } 119 | return Pattern.matches("^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$", str.trim()); 120 | } 121 | 122 | public static boolean isEmpty(String password) { 123 | return password == null || "".equals(password); 124 | } 125 | 126 | /** 127 | * 获取ip地址 128 | * @param request 129 | * @return 130 | */ 131 | public static String getIpAddr(HttpServletRequest request) { 132 | String ip = request.getHeader("X-Real-IP"); 133 | if (!isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { 134 | return ip; 135 | } 136 | ip = request.getHeader("X-Forwarded-For"); 137 | if (!isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { 138 | // 多次反向代理后会有多个IP值,第一个为真实IP。 139 | int index = ip.indexOf(','); 140 | if (index != -1) { 141 | return ip.substring(0, index); 142 | } else { 143 | return ip; 144 | } 145 | } else { 146 | return request.getRemoteAddr(); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8989 3 | spring: 4 | application: 5 | name: JavaRun 6 | datasource: 7 | type: com.alibaba.druid.pool.DruidDataSource 8 | driver-class-name: com.mysql.jdbc.Driver 9 | url: jdbc:mysql://localhost:3306/short_url?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false 10 | username: root 11 | password: root 12 | thymeleaf: 13 | prefix: classpath:/templates/ 14 | suffix: .html 15 | mode: HTML5 16 | encoding: UTF-8 17 | cache: false 18 | servlet: 19 | content-type: text/html 20 | web: 21 | resources: 22 | chain: 23 | strategy: 24 | content: 25 | enabled: true 26 | paths: /** 27 | devtools: 28 | restart: 29 | enabled: true 30 | additional-paths: src/main/java 31 | mvc: 32 | static-path-pattern: static/** 33 | 34 | mybatis: 35 | mapper-locations: classpath:mapper/*.xml 36 | type-aliases-package: com.rawchen.shorturl.entity 37 | configuration: 38 | map-underscore-to-camel-case: true 39 | # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 40 | 41 | logging: 42 | level: 43 | #控制台打印mapper接口的sql语句日志 44 | com.rawchen.shorturl.mapper: debug -------------------------------------------------------------------------------- /src/main/resources/mapper/LogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | id, browser_name, os_name, api_path, ip, referer, access_time, short_url_id 27 | 28 | 29 | 30 | ua 31 | 32 | 33 | 41 | 42 | 45 | 46 | 50 | 51 | 54 | 55 | 58 | 59 | 62 | 63 | 66 | 67 | 70 | 71 | 74 | 75 | 102 | 103 | 132 | 133 | 134 | insert into log (id, browser_name, os_name, 135 | api_path, ip, referer, 136 | access_time, short_url_id, ua 137 | ) 138 | values (#{id}, #{browserName}, #{osName}, 139 | #{apiPath}, #{ip}, #{referer}, 140 | #{accessTime}, #{shortUrlId}, #{ua} 141 | ) 142 | 143 | -------------------------------------------------------------------------------- /src/main/resources/mapper/UrlMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | id, code, link, effective_date 17 | 18 | 19 | INSERT INTO short_url(code, link, effective_date, password, ip, save_time) VALUES (#{code}, #{link}, #{effectiveDate}, #{password}, #{ip}, #{saveTime}) 20 | 21 | 22 | 23 | DELETE FROM short_url 24 | WHERE effective_date > CURDATE() 25 | 26 | 27 | 34 | 39 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/css/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/bootstrap-3.3.7/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /src/main/resources/static/css/error.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-image: url(../img/bg.png); 3 | background-position: left top; 4 | background-size: auto; 5 | background-repeat: repeat; 6 | background-attachment: fixed; 7 | background-color: #f7f7f7!important; 8 | margin:0;padding:0; 9 | font-family: PingFang SC,Microsoft YaHei,WenQuanYi Micro Hei,sans-serif; 10 | } 11 | a, button.submit { 12 | color:#6E7173; 13 | text-decoration:none; 14 | -webkit-transition:all .1s ease-in; 15 | -moz-transition:all .1s ease-in; 16 | -o-transition:all .1s ease-in; 17 | transition:all .1s ease-in; 18 | } 19 | a:hover, a:active { 20 | color:#6E7173; 21 | } 22 | .body404{ 23 | position: absolute; 24 | height: 100%; 25 | width: 100%; 26 | } 27 | .body-about .body404{ 28 | } 29 | .site-name404 { 30 | font-family: cursive; 31 | margin: 0 auto; 32 | text-align: center; 33 | letter-spacing: 2px; 34 | font-size: 150px; 35 | line-height: 1; 36 | font-weight: 700; 37 | color: #f35626; 38 | background-image: -webkit-linear-gradient(92deg,#f35626,#feab3a); 39 | -webkit-background-clip: text; 40 | -webkit-text-fill-color: transparent; 41 | -webkit-animation: hue 60s infinite linear; 42 | } 43 | 44 | @media screen and (max-width: 500px) { 45 | .site-name404 { 46 | font-size: 69px; 47 | letter-spacing: -7px; 48 | } 49 | } 50 | 51 | .site-name404 h1{ 52 | margin: 0 0 10px; 53 | font-size:50px; 54 | line-height:1.2; 55 | } 56 | .title404 span{ 57 | font-weight: 700; 58 | } 59 | .title404 p{ 60 | font-size: 20px; 61 | line-height:1.5; 62 | margin:0; 63 | color:#7b8993; 64 | } 65 | .info404{ 66 | position: absolute; 67 | top: 50%; 68 | text-align: center; 69 | width: 100%; 70 | margin-top: -160px; 71 | } 72 | .body-about .info404{ 73 | margin-top: -180px; 74 | } 75 | #footer404{ 76 | margin-top:30px; 77 | font-size:10px; 78 | } 79 | .index404 { 80 | margin-top: 24px; 81 | display: inline-block; 82 | white-space: nowrap; 83 | cursor: pointer; 84 | letter-spacing: 1px; 85 | font-size: 14px; 86 | -moz-user-select: -moz-none; 87 | -webkit-user-select: none; 88 | -ms-user-select: none; 89 | -o-user-select: none; 90 | user-select: none; 91 | text-shadow: none; 92 | border: 2px solid #7b8993; 93 | line-height: 36px; 94 | text-align: center; 95 | height: 36px; 96 | padding: 0 25px; 97 | border-radius: 25px; 98 | background-color: #fff; 99 | color: #7b8993; 100 | } 101 | .icon-about{ 102 | padding: 10px 0 25px; 103 | } 104 | .icon-about a{ 105 | font-size: 20px; 106 | margin: 5px; 107 | color: #fff; 108 | background-color: #000; 109 | border-radius: 100%; 110 | padding: 6px; 111 | } 112 | @-webkit-keyframes hue { 113 | from { 114 | -webkit-filter: hue-rotate(0deg); 115 | } 116 | 117 | to { 118 | -webkit-filter: hue-rotate(-360deg); 119 | } 120 | } -------------------------------------------------------------------------------- /src/main/resources/static/datepicker/datepicker.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Datepicker v0.6.4 3 | * https://github.com/fengyuanchen/datepicker 4 | * 5 | * Copyright (c) 2014-2017 Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2017-11-24T14:38:19.628Z 9 | */.datepicker-container{background-color:#fff;direction:ltr;font-size:12px;left:0;line-height:30px;position:fixed;top:0;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:210px;z-index:-1;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.datepicker-container:after,.datepicker-container:before{border:5px solid transparent;content:" ";display:block;height:0;position:absolute;width:0}.datepicker-dropdown{border:1px solid #ccc;box-shadow:0 3px 6px #ccc;box-sizing:content-box;position:absolute;z-index:1}.datepicker-inline{position:static}.datepicker-top-left,.datepicker-top-right{border-top-color:#39f}.datepicker-top-left:after,.datepicker-top-left:before,.datepicker-top-right:after,.datepicker-top-right:before{border-top:0;left:10px;top:-5px}.datepicker-top-left:before,.datepicker-top-right:before{border-bottom-color:#39f}.datepicker-top-left:after,.datepicker-top-right:after{border-bottom-color:#fff;top:-4px}.datepicker-bottom-left,.datepicker-bottom-right{border-bottom-color:#39f}.datepicker-bottom-left:after,.datepicker-bottom-left:before,.datepicker-bottom-right:after,.datepicker-bottom-right:before{border-bottom:0;bottom:-5px;left:10px}.datepicker-bottom-left:before,.datepicker-bottom-right:before{border-top-color:#39f}.datepicker-bottom-left:after,.datepicker-bottom-right:after{border-top-color:#fff;bottom:-4px}.datepicker-bottom-right:after,.datepicker-bottom-right:before,.datepicker-top-right:after,.datepicker-top-right:before{left:auto;right:10px}.datepicker-panel>ul{margin:0;padding:0;width:102%}.datepicker-panel>ul:after,.datepicker-panel>ul:before{content:" ";display:table}.datepicker-panel>ul:after{clear:both}.datepicker-panel>ul>li{background-color:#fff;cursor:pointer;float:left;height:30px;list-style:none;margin:0;padding:0;text-align:center;width:30px}.datepicker-panel>ul>li:hover{background-color:#e5f2ff}.datepicker-panel>ul>li.muted,.datepicker-panel>ul>li.muted:hover{color:#999}.datepicker-panel>ul>li.highlighted{background-color:#e5f2ff}.datepicker-panel>ul>li.highlighted:hover{background-color:#cce5ff}.datepicker-panel>ul>li.picked,.datepicker-panel>ul>li.picked:hover{color:#39f}.datepicker-panel>ul>li.disabled,.datepicker-panel>ul>li.disabled:hover{background-color:#fff;color:#ccc;cursor:default}.datepicker-panel>ul>li.disabled.highlighted,.datepicker-panel>ul>li.disabled:hover.highlighted{background-color:#e5f2ff}.datepicker-panel>ul>li[data-view="month next"],.datepicker-panel>ul>li[data-view="month prev"],.datepicker-panel>ul>li[data-view="year next"],.datepicker-panel>ul>li[data-view="year prev"],.datepicker-panel>ul>li[data-view="years next"],.datepicker-panel>ul>li[data-view="years prev"],.datepicker-panel>ul>li[data-view=next]{font-size:18px}.datepicker-panel>ul>li[data-view="month current"],.datepicker-panel>ul>li[data-view="year current"],.datepicker-panel>ul>li[data-view="years current"]{width:150px}.datepicker-panel>ul[data-view=months]>li,.datepicker-panel>ul[data-view=years]>li{height:52.5px;line-height:52.5px;width:52.5px}.datepicker-panel>ul[data-view=week]>li,.datepicker-panel>ul[data-view=week]>li:hover{background-color:#fff;cursor:default}.datepicker-hide{display:none} -------------------------------------------------------------------------------- /src/main/resources/static/datepicker/datepicker.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Datepicker v0.6.4 3 | * https://github.com/fengyuanchen/datepicker 4 | * 5 | * Copyright (c) 2014-2017 Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2017-11-24T14:38:23.820Z 9 | */ 10 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):t(e.jQuery)}(this,function(e){"use strict";function t(e){return"string"==typeof e}function i(e){return"number"==typeof e&&!v(e)}function a(e){return void 0===e}function s(e){return"date"===function(e){return y.call(e).slice(8,-1).toLowerCase()}(e)}function n(e,t){for(var i=arguments.length,a=Array(i>2?i-2:0),s=2;s

          ',offset:10,zIndex:1e3,filter:null,show:null,hide:null,pick:null},d="undefined"!=typeof window?window:{},u="datepicker",c="click.datepicker",p="datepicker-hide",f={},g={DAYS:0,MONTHS:1,YEARS:2},y=Object.prototype.toString,v=Number.isNaN||d.isNaN,m=/(y|m|d)+/g,w=/\d+/g,k={show:function(){this.built||this.build(),this.shown||this.trigger("show.datepicker").isDefaultPrevented()||(this.shown=!0,this.$picker.removeClass(p).on(c,e.proxy(this.click,this)),this.showView(this.options.startView),this.inline||(e(window).on("resize.datepicker",this.onResize=n(this.place,this)),e(document).on(c,this.onGlobalClick=n(this.globalClick,this)),e(document).on("keyup.datepicker",this.onGlobalKeyup=n(this.globalKeyup,this)),this.place()))},hide:function(){this.shown&&(this.trigger("hide.datepicker").isDefaultPrevented()||(this.shown=!1,this.$picker.addClass(p).off(c,this.click),this.inline||(e(window).off("resize.datepicker",this.onResize),e(document).off(c,this.onGlobalClick),e(document).off("keyup.datepicker",this.onGlobalKeyup))))},toggle:function(){this.shown?this.hide():this.show()},update:function(){var e=this.getValue();e!==this.oldValue&&(this.setDate(e,!0),this.oldValue=e)},pick:function(e){var t=this.$element,i=this.date;this.trigger("pick.datepicker",{view:e||"",date:i}).isDefaultPrevented()||(i=this.formatDate(this.date),this.setValue(i),this.isInput&&(t.trigger("input"),t.trigger("change")))},reset:function(){this.setDate(this.initialDate,!0),this.setValue(this.initialValue),this.shown&&this.showView(this.options.startView)},getMonthName:function(t,s){var n=this.options,r=n.monthsShort,h=n.months;return e.isNumeric(t)?t=Number(t):a(s)&&(s=t),!0===s&&(h=r),h[i(t)?t:this.date.getMonth()]},getDayName:function(t,s,n){var r=this.options,h=r.days;return e.isNumeric(t)?t=Number(t):(a(n)&&(n=s),a(s)&&(s=t)),n?h=r.daysMin:s&&(h=r.daysShort),h[i(t)?t:this.date.getDay()]},getDate:function(e){var t=this.date;return e?this.formatDate(t):new Date(t)},setDate:function(i,a){var n=this.options.filter;if(s(i)||t(i)){if(i=this.parseDate(i),e.isFunction(n)&&!1===n.call(this.$element,i))return;this.date=i,this.viewDate=new Date(i),a||this.pick(),this.built&&this.render()}},setStartDate:function(e){(s(e)||t(e))&&(this.startDate=this.parseDate(e),this.built&&this.render())},setEndDate:function(e){(s(e)||t(e))&&(this.endDate=this.parseDate(e),this.built&&this.render())},parseDate:function(i){var a=this.format,n=[];if(s(i))return new Date(i.getFullYear(),i.getMonth(),i.getDate());t(i)&&(n=i.match(w)||[]),i=new Date;var r=a.parts.length,h=i.getFullYear(),o=i.getDate(),l=i.getMonth();return n.length===r&&e.each(n,function(e,t){var i=parseInt(t,10)||1;switch(a.parts[e]){case"dd":case"d":o=i;break;case"mm":case"m":l=i-1;break;case"yy":h=2e3+i;break;case"yyyy":h=i}}),new Date(h,l,o)},formatDate:function(t){var i=this.format,a="";if(s(t)){var n=t.getFullYear(),r={d:t.getDate(),m:t.getMonth()+1,yy:n.toString().substring(2),yyyy:n};r.dd=(r.d<10?"0":"")+r.d,r.mm=(r.m<10?"0":"")+r.m,a=i.source,e.each(i.parts,function(e,t){a=a.replace(t,r[t])})}return a},destroy:function(){this.unbind(),this.unbuild(),this.$element.removeData(u)}},D={click:function(t){var i=e(t.target),a=this.options,s=this.viewDate,n=this.format;if(t.stopPropagation(),t.preventDefault(),!i.hasClass("disabled")){var r=i.data("view"),h=s.getFullYear(),l=s.getMonth(),d=s.getDate();switch(r){case"years prev":case"years next":h="years prev"===r?h-10:h+10,this.viewDate=new Date(h,l,o(h,l,d)),this.renderYears();break;case"year prev":case"year next":h="year prev"===r?h-1:h+1,this.viewDate=new Date(h,l,o(h,l,d)),this.renderMonths();break;case"year current":n.hasYear&&this.showView(g.YEARS);break;case"year picked":n.hasMonth?this.showView(g.MONTHS):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("year");break;case"year":h=parseInt(i.text(),10),this.date=new Date(h,l,o(h,l,d)),n.hasMonth?(this.viewDate=new Date(this.date),this.showView(g.MONTHS)):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("year");break;case"month prev":case"month next":(l="month prev"===r?l-1:l+1)<0?(h-=1,l+=12):l>11&&(h+=1,l-=12),this.viewDate=new Date(h,l,o(h,l,d)),this.renderDays();break;case"month current":n.hasMonth&&this.showView(g.MONTHS);break;case"month picked":n.hasDay?this.showView(g.DAYS):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("month");break;case"month":l=e.inArray(i.text(),a.monthsShort),this.date=new Date(h,l,o(h,l,d)),n.hasDay?(this.viewDate=new Date(h,l,o(h,l,d)),this.showView(g.DAYS)):(i.addClass(a.pickedClass).siblings().removeClass(a.pickedClass),this.hideView()),this.pick("month");break;case"day prev":case"day next":case"day":"day prev"===r?l-=1:"day next"===r&&(l+=1),d=parseInt(i.text(),10),this.date=new Date(h,l,d),this.viewDate=new Date(h,l,d),this.renderDays(),"day"===r&&this.hideView(),this.pick("day");break;case"day picked":this.hideView(),this.pick("day")}}},globalClick:function(e){for(var t=e.target,i=this.element,a=this.$trigger[0],s=!0;t!==document;){if(t===a||t===i){s=!1;break}t=t.parentNode}s&&this.hide()},keyup:function(){this.update()},globalKeyup:function(e){var t=e.target,i=e.key,a=e.keyCode;this.isInput&&t!==this.element&&this.shown&&("Tab"===i||9===a)&&this.hide()}},b={render:function(){this.renderYears(),this.renderMonths(),this.renderDays()},renderWeek:function(){var t=this,i=[],a=this.options,s=a.weekStart,n=a.daysMin;s=parseInt(s,10)%7,n=n.slice(s).concat(n.slice(0,s)),e.each(n,function(e,a){i.push(t.createItem({text:a}))}),this.$week.html(i.join(""))},renderYears:function(){var e=this.options,t=this.startDate,i=this.endDate,a=e.disabledClass,s=e.filter,n=e.yearSuffix,r=this.viewDate.getFullYear(),h=(new Date).getFullYear(),o=this.date.getFullYear(),l=[],d=!1,u=!1,c=void 0;for(c=-5;c<=6;c+=1){var p=new Date(r+c,1,1),f=!1;t&&(f=p.getFullYear()i.getFullYear(),6===c&&(u=f)),!f&&s&&(f=!1===s.call(this.$element,p));var g=r+c===o,y=g?"year picked":"year";l.push(this.createItem({picked:g,disabled:f,muted:-5===c||6===c,text:r+c,view:f?"year disabled":y,highlighted:p.getFullYear()===h}))}this.$yearsPrev.toggleClass(a,d),this.$yearsNext.toggleClass(a,u),this.$yearsCurrent.toggleClass(a,!0).html(r+-5+n+" - "+(r+6)+n),this.$years.html(l.join(""))},renderMonths:function(){var t=this.options,i=this.startDate,a=this.endDate,s=this.viewDate,n=t.disabledClass||"",r=t.monthsShort,h=e.isFunction(t.filter)&&t.filter,o=s.getFullYear(),l=new Date,d=l.getFullYear(),u=l.getMonth(),c=this.date.getFullYear(),p=this.date.getMonth(),f=[],g=!1,y=!1,v=void 0;for(v=0;v<=11;v+=1){var m=new Date(o,v,1),w=!1;i&&(w=(g=m.getFullYear()===i.getFullYear())&&m.getMonth()a.getMonth()),!w&&h&&(w=!1===h.call(this.$element,m));var k=o===c&&v===p,D=k?"month picked":"month";f.push(this.createItem({disabled:w,picked:k,highlighted:o===d&&m.getMonth()===u,index:v,text:r[v],view:w?"month disabled":D}))}this.$yearPrev.toggleClass(n,g),this.$yearNext.toggleClass(n,y),this.$yearCurrent.toggleClass(n,g&&y).html(o+t.yearSuffix||""),this.$months.html(f.join(""))},renderDays:function(){var e=this.$element,t=this.options,i=this.startDate,a=this.endDate,s=this.viewDate,n=this.date,r=t.disabledClass,o=t.filter,l=t.monthsShort,d=t.weekStart,u=t.yearSuffix,c=s.getFullYear(),p=s.getMonth(),f=new Date,g=f.getFullYear(),y=f.getMonth(),v=f.getDate(),m=n.getFullYear(),w=n.getMonth(),k=n.getDate(),D=void 0,b=void 0,C=void 0,$=[],x=c,M=p,S=!1;0===p?(x-=1,M=11):M-=1,D=h(x,M);var F=new Date(c,p,1);for((C=F.getDay()-parseInt(d,10)%7)<=0&&(C+=7),i&&(S=F.getTime()<=i.getTime()),b=D-(C-1);b<=D;b+=1){var Y=new Date(x,M,b),T=!1;i&&(T=Y.getTime()=a.getTime()),b=1;b<=C;b+=1){var j=new Date(I,N,b),O=I===m&&N===w&&b===k,H=!1;a&&(H=j.getTime()>a.getTime()),!H&&o&&(H=!1===o.call(e,j)),V.push(this.createItem({disabled:H,picked:O,highlighted:I===g&&N===y&&j.getDate()===v,muted:!0,text:b,view:"day next"}))}var q=[];for(b=1;b<=D;b+=1){var E=new Date(c,p,b),z=!1;i&&(z=E.getTime()a.getTime()),!z&&o&&(z=!1===o.call(e,E));var W=c===m&&p===w&&b===k,J=W?"day picked":"day";q.push(this.createItem({disabled:z,picked:W,highlighted:c===g&&p===y&&E.getDate()===v,text:b,view:z?"day disabled":J}))}this.$monthPrev.toggleClass(r,S),this.$monthNext.toggleClass(r,P),this.$monthCurrent.toggleClass(r,S&&P).html(t.yearFirst?c+u+" "+l[p]:l[p]+" "+c+u),this.$days.html($.join("")+q.join("")+V.join(""))}},C=function(){function e(e,t){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t),this.$element=e(i),this.element=i,this.options=e.extend({},l,f[a.language],a),this.built=!1,this.shown=!1,this.isInput=!1,this.inline=!1,this.initialValue="",this.initialDate=null,this.startDate=null,this.endDate=null,this.init()}return C(t,[{key:"init",value:function(){var t=this.$element,i=this.options,a=i.startDate,s=i.endDate,n=i.date;this.$trigger=e(i.trigger),this.isInput=t.is("input")||t.is("textarea"),this.inline=i.inline&&(i.container||!this.isInput),this.format=function(t){var i=String(t).toLowerCase(),a=i.match(m);if(!a||0===a.length)throw new Error("Invalid date format.");return t={source:i,parts:a},e.each(a,function(e,i){switch(i){case"dd":case"d":t.hasDay=!0;break;case"mm":case"m":t.hasMonth=!0;break;case"yyyy":case"yy":t.hasYear=!0}}),t}(i.format);var r=this.getValue();this.initialValue=r,this.oldValue=r,n=this.parseDate(n||r),a&&(a=this.parseDate(a),n.getTime()s.getTime()&&(n=new Date(s)),this.endDate=s),this.date=n,this.viewDate=new Date(n),this.initialDate=new Date(this.date),this.bind(),(i.autoShow||this.inline)&&this.show(),i.autoPick&&this.pick()}},{key:"build",value:function(){if(!this.built){this.built=!0;var t=this.$element,i=this.options,a=e(i.template);this.$picker=a,this.$week=a.find(r("week")),this.$yearsPicker=a.find(r("years picker")),this.$yearsPrev=a.find(r("years prev")),this.$yearsNext=a.find(r("years next")),this.$yearsCurrent=a.find(r("years current")),this.$years=a.find(r("years")),this.$monthsPicker=a.find(r("months picker")),this.$yearPrev=a.find(r("year prev")),this.$yearNext=a.find(r("year next")),this.$yearCurrent=a.find(r("year current")),this.$months=a.find(r("months")),this.$daysPicker=a.find(r("days picker")),this.$monthPrev=a.find(r("month prev")),this.$monthNext=a.find(r("month next")),this.$monthCurrent=a.find(r("month current")),this.$days=a.find(r("days")),this.inline?e(i.container||t).append(a.addClass("datepicker-inline")):(e(document.body).append(a.addClass("datepicker-dropdown")),a.addClass(p)),this.renderWeek()}}},{key:"unbuild",value:function(){this.built&&(this.built=!1,this.$picker.remove())}},{key:"bind",value:function(){var t=this.options,i=this.$element;e.isFunction(t.show)&&i.on("show.datepicker",t.show),e.isFunction(t.hide)&&i.on("hide.datepicker",t.hide),e.isFunction(t.pick)&&i.on("pick.datepicker",t.pick),this.isInput&&i.on("keyup.datepicker",e.proxy(this.keyup,this)),this.inline||(t.trigger?this.$trigger.on(c,e.proxy(this.toggle,this)):this.isInput?i.on("focus.datepicker",e.proxy(this.show,this)):i.on(c,e.proxy(this.show,this)))}},{key:"unbind",value:function(){var t=this.$element,i=this.options;e.isFunction(i.show)&&t.off("show.datepicker",i.show),e.isFunction(i.hide)&&t.off("hide.datepicker",i.hide),e.isFunction(i.pick)&&t.off("pick.datepicker",i.pick),this.isInput&&t.off("keyup.datepicker",this.keyup),this.inline||(i.trigger?this.$trigger.off(c,this.toggle):this.isInput?t.off("focus.datepicker",this.show):t.off(c,this.show))}},{key:"showView",value:function(e){var t=this.$yearsPicker,i=this.$monthsPicker,a=this.$daysPicker,s=this.format;if(s.hasYear||s.hasMonth||s.hasDay)switch(Number(e)){case g.YEARS:i.addClass(p),a.addClass(p),s.hasYear?(this.renderYears(),t.removeClass(p),this.place()):this.showView(g.DAYS);break;case g.MONTHS:t.addClass(p),a.addClass(p),s.hasMonth?(this.renderMonths(),i.removeClass(p),this.place()):this.showView(g.YEARS);break;default:t.addClass(p),i.addClass(p),s.hasDay?(this.renderDays(),a.removeClass(p),this.place()):this.showView(g.MONTHS)}}},{key:"hideView",value:function(){!this.inline&&this.options.autoHide&&this.hide()}},{key:"place",value:function(){if(!this.inline){var t=this.$element,i=this.options,a=this.$picker,s=e(document).outerWidth(),n=e(document).outerHeight(),r=t.outerWidth(),h=t.outerHeight(),o=a.width(),l=a.height(),d=t.offset(),u=d.left,c=d.top,p=parseFloat(i.offset),f=$;v(p)&&(p=10),c>l&&c+h+l>n?(c-=l+p,f=x):c+=h+p,u+o>s&&(u+=r-o,f=f.replace("left","right")),a.removeClass(M).addClass(f).css({top:c,left:u,zIndex:parseInt(i.zIndex,10)})}}},{key:"trigger",value:function(t,i){var a=e.Event(t,i);return this.$element.trigger(a),a}},{key:"createItem",value:function(t){var i=this.options,a=i.itemTag,s={text:"",view:"",muted:!1,picked:!1,disabled:!1,highlighted:!1},n=[];return e.extend(s,t),s.muted&&n.push(i.mutedClass),s.highlighted&&n.push(i.highlightedClass),s.picked&&n.push(i.pickedClass),s.disabled&&n.push(i.disabledClass),"<"+a+' class="'+n.join(" ")+'" data-view="'+s.view+'">'+s.text+""}},{key:"getValue",value:function(){var e=this.$element;return this.isInput?e.val():e.text()}},{key:"setValue",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=this.$element;this.isInput?t.val(e):t.text(e)}}],[{key:"setDefaults",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};e.extend(l,f[t.language],t)}}]),t}();if(e.extend&&e.extend(S.prototype,b,D,k),e.fn){var F=e.fn.datepicker;e.fn.datepicker=function(i){for(var s=arguments.length,n=Array(s>1?s-1:0),r=1;r 0){ 12 | $('[data-toggle="datepicker"]').datepicker({ 13 | autoPick: false, 14 | autoHide: true, 15 | format: "yyyy/mm/dd", 16 | days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], 17 | daysShort:["周日","周一","周二","周三","周四","周五","周六"], 18 | daysMin:["日","一","二","三","四","五","六"], 19 | months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"], 20 | monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"], 21 | startDate: new Date() 22 | }); 23 | } 24 | 25 | $(window).scroll(function(){ 26 | if(window.pageYOffset>300){ 27 | $("#backtop,#back-to-top").fadeIn('slow'); 28 | }else{ 29 | $("#backtop,#back-to-top").fadeOut('slow'); 30 | } 31 | }); 32 | $("a#back-to-top").smoothscroll(); 33 | 34 | document.getElementById("longurl").focus(); 35 | }); 36 | 37 | function isUrl(str) { 38 | const v = new RegExp('^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i'); 39 | return v.test(str); 40 | } 41 | 42 | function doSubmit() { 43 | var link = $("#longurl").val().trim(); 44 | if (isUrl(link)) { 45 | if ($("#expiry").val() !== "") { 46 | regex = /^\d{4}[\/](0?[1-9]|1[012])[\/](0?[1-9]|[12][0-9]|3[01])$/; 47 | if (!regex.test($("#expiry").val().trim())) { 48 | $("#expiry").focus(); 49 | layer.msg('日期格式不正确', {icon: 2,closeBtn: 2}); 50 | return; 51 | } 52 | } 53 | 54 | // 如果包含本域名 55 | if (link.indexOf(window.location.host) !== -1) { 56 | document.getElementById("longurl").focus(); 57 | layer.msg('不允许循环哦', {icon: 2,closeBtn: 2}); 58 | return; 59 | } 60 | const btnObject = document.getElementById('shortenurl'); 61 | btnObject.innerHTML = '立即缩短(10)'; 62 | btnObject.disabled = true; 63 | let sec = 10; 64 | let intervalId = setInterval(function () { 65 | if (sec > 0) { 66 | btnObject.innerHTML = '立即缩短(' + sec + ')'; 67 | btnObject.disabled = true; 68 | sec--; 69 | } else { 70 | btnObject.innerHTML = '立即缩短'; 71 | btnObject.disabled = false; 72 | clearInterval(intervalId); 73 | } 74 | }, 1000); 75 | $.ajax({ 76 | //几个参数需要注意一下 77 | type: "POST",//方法类型 78 | dataType: "json",//预期服务器返回的数据类型 79 | url: "/insert",//url 80 | headers: {'content-type': 'application/json'}, 81 | data: JSON.stringify({"longUrl": decodeURI(link), "effectiveDate": $('#expiry').val(), "password": $('#pass').val()}), 82 | success: function (result) { 83 | if (result.code === 200) { 84 | 85 | let link = document.location.protocol + "//" + window.location.host + "/" + result.msg; 86 | 87 | $('.ajax').hide().html('
          网址已成功缩短
          ').fadeIn('slow'); 88 | $('.share-this').html('

          短网址

          ' + link + '
          复制

          短网址二维码
          ').fadeIn('slow'); 89 | $("#copyurl").attr("data-clipboard-text", link).show(); 90 | var copy = new Clipboard('#copyurl'); 91 | copy.on('success', function(e) { 92 | layer.msg('短链已复制到剪贴板', {icon: 1,closeBtn: 2}); 93 | }); 94 | } else if (result.code === 400) { 95 | layer.msg(result.msg, {icon: 2,closeBtn: 2}); 96 | } else if (result.code === 500) { 97 | layer.msg(result.msg, {icon: 3,closeBtn: 2}); 98 | } 99 | }, 100 | error: function () { 101 | layer.msg('异常', {icon: 3,closeBtn: 2}); 102 | } 103 | }); 104 | } else { 105 | document.getElementById("longurl").focus(); 106 | layer.msg('URL格式不正确', {icon: 2,closeBtn: 2}); 107 | } 108 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v1.5.15 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Clipboard=e()}}(function(){var e,t,n;return function e(t,n,i){function o(a,c){if(!n[a]){if(!t[a]){var l="function"==typeof require&&require;if(!c&&l)return l(a,!0);if(r)return r(a,!0);var s=new Error("Cannot find module '"+a+"'");throw s.code="MODULE_NOT_FOUND",s}var u=n[a]={exports:{}};t[a][0].call(u.exports,function(e){var n=t[a][1][e];return o(n?n:e)},u,u.exports,e,t,n,i)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a0&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function e(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function e(){var t=this,n="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=document.body.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[n?"right":"left"]="-9999px";var i=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.addEventListener("focus",window.scrollTo(0,i)),this.fakeElem.style.top=i+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=(0,o.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function e(){this.fakeHandler&&(document.body.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function e(){this.selectedText=(0,o.default)(this.target),this.copyText()}},{key:"copyText",value:function e(){var t=void 0;try{t=document.execCommand(this.action)}catch(e){t=!1}this.handleResult(t)}},{key:"handleResult",value:function e(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function e(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function e(){this.removeFake()}},{key:"action",set:function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function e(){return this._action}},{key:"target",set:function e(t){if(void 0!==t){if(!t||"object"!==("undefined"==typeof t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function e(){return this._target}}]),e}();e.exports=c})},{select:5}],8:[function(t,n,i){!function(o,r){if("function"==typeof e&&e.amd)e(["module","./clipboard-action","tiny-emitter","good-listener"],r);else if("undefined"!=typeof i)r(n,t("./clipboard-action"),t("tiny-emitter"),t("good-listener"));else{var a={exports:{}};r(a,o.clipboardAction,o.tinyEmitter,o.goodListener),o.clipboard=a.exports}}(this,function(e,t,n,i){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function c(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n="data-clipboard-"+e;if(t.hasAttribute(n))return t.getAttribute(n)}var s=o(t),u=o(n),f=o(i),d=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText}},{key:"listenClick",value:function e(t){var n=this;this.listener=(0,f.default)(t,"click",function(e){return n.onClick(e)})}},{key:"onClick",value:function e(t){var n=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new s.default({action:this.action(n),target:this.target(n),text:this.text(n),trigger:n,emitter:this})}},{key:"defaultAction",value:function e(t){return l("action",t)}},{key:"defaultTarget",value:function e(t){var n=l("target",t);if(n)return document.querySelector(n)}},{key:"defaultText",value:function e(t){return l("text",t)}},{key:"destroy",value:function e(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}]),t}(u.default);e.exports=h})},{"./clipboard-action":7,"good-listener":4,"tiny-emitter":6}]},{},[8])(8)}); -------------------------------------------------------------------------------- /src/main/resources/static/layer/layer.js: -------------------------------------------------------------------------------- 1 | /*! layer-v3.5.1 Web 通用弹出层组件 MIT License */ 2 | ;!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var t=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;n>0;n--)if("interactive"===t[n].readyState){e=t[n].src;break}return e||t[i].src}(),i=e.LAYUI_GLOBAL||{};return i.layer_dir||t.substring(0,t.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"],getStyle:function(t,i){var n=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return n[n.getPropertyValue?"getPropertyValue":"getAttribute"](i)},link:function(t,i,n){if(r.path){var a=document.getElementsByTagName("head")[0],s=document.createElement("link");"string"==typeof i&&(n=i);var l=(n||t).replace(/\.|\//g,""),f="layuicss-"+l,c="creating",u=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,document.getElementById(f)||a.appendChild(s),"function"==typeof i&&!function d(t){var n=100,a=document.getElementById(f);return++u>1e4/n?e.console&&console.error(l+".css: Invalid"):void(1989===parseInt(o.getStyle(a,"width"))?(t===c&&a.removeAttribute("lay-status"),a.getAttribute("lay-status")===c?setTimeout(d,n):i()):(a.setAttribute("lay-status",c),setTimeout(function(){d(c)},n)))}()}}},r={v:"3.5.1",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):o.link("theme/"+e.extend),this):this},ready:function(e){var t="layer",i="",n=(a?"modules/layer/":"theme/")+"default/layer.css?v="+r.v+i;return a?layui.addcss(n,e,t):o.link(n,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:260},n))}},s=function(e){var t=this,a=function(){t.creat()};t.index=++r.index,t.config.maxWidth=i(n).width()-30,t.config=i.extend({},t.config,o.config,e),document.body?a():setTimeout(function(){a()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim-00","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],l.SHADE="layui-layer-shade",l.MOVE="layui-layer-move",s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,minStack:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
          '+(f?r.title[0]:r.title)+"
          ":"";return r.zIndex=s,t([r.shade?'
          ':"",'
          '+(e&&2!=r.type?"":u)+'
          '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
          '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
          '+e+"
          "}():"")+(r.resize?'':"")+"
          "],u,i('
          ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}if(e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i("#"+l.MOVE)[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),e.shadeo=i("#"+l.SHADE+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),e.shadeo.css({"background-color":t.shade[1]||"#000",opacity:t.shade[0]||t.shade}),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():function(){e.offset(),parseInt(o.getStyle(document.getElementById(l.MOVE),"z-index"))||function(){e.layero.css("visibility","hidden"),r.ready(function(){e.offset(),e.layero.css("visibility","visible")})}()}(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]){var u="layer-anim "+l.anim[t.anim];e.layero.addClass(u).one("webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend",function(){i(this).removeClass(u)})}t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){var t=this,a=t.config,o=i("#"+l[0]+e);""===a.area[0]&&a.maxWidth>0&&(r.ie&&r.ie<8&&a.btn&&o.width(o.innerWidth()),o.outerWidth()>a.maxWidth&&o.width(a.maxWidth));var s=[o.innerWidth(),o.innerHeight()],f=o.find(l[1]).outerHeight()||0,c=o.find("."+l[6]).outerHeight()||0,u=function(e){e=o.find(e),e.height(s[1]-f-c-2*(0|parseFloat(e.css("padding-top"))))};switch(a.type){case 2:u("iframe");break;default:""===a.area[1]?a.maxHeight>0&&o.outerHeight()>a.maxHeight?(s[1]=a.maxHeight,u("."+l[5])):a.fixed&&s[1]>=n.height()&&(s[1]=n.height(),u("."+l[5])):u("."+l[5])}return t},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&t.shadeo.on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n,t.index);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n,t.index)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n,t.index)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){t=t||{};var a=i("#"+l[0]+e),s=i("#"+l.SHADE+e),f=a.find(l[1]).outerHeight()||0,c=a.attr("minLeft")||181*o.minIndex+"px",u=a.css("position"),d={width:180,height:f,position:"fixed",overflow:"hidden"};o.record(a),o.minLeft[0]&&(c=o.minLeft[0],o.minLeft.shift()),t.minStack&&(d.left=c,d.top=n.height()-f,a.attr("minLeft")||o.minIndex++,a.attr("minLeft",c)),a.attr("position",u),r.style(e,d,!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),s.hide()},r.restore=function(e){var t=i("#"+l[0]+e),n=i("#"+l.SHADE+e),a=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(a[0]),height:parseFloat(a[1]),top:parseFloat(a[2]),left:parseFloat(a[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e),n.show()},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e,t){var n=i("#"+l[0]+e),a=n.attr("type"),s="layer-anim-close";if(n[0]){var f="layui-layer-wrap",c=function(){if(a===o.type[1]&&"object"===n.attr("conType")){n.children(":not(."+l[5]+")").remove();for(var r=n.find("."+f),s=0;s<2;s++)r.unwrap();r.css("display",r.data("display")).removeClass(f)}else{if(a===o.type[2])try{var c=i("#"+l[4]+e)[0];c.contentWindow.document.write(""),c.contentWindow.close(),n.find("."+l[5])[0].removeChild(c)}catch(u){}n[0].innerHTML="",n.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e],"function"==typeof t&&t()};n.data("isOutAnim")&&n.addClass("layer-anim "+s),i("#layui-layer-moves, #"+l.SHADE+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),n.attr("minLeft")&&(o.minIndex--,o.minLeft.push(n.attr("minLeft"))),r.ie&&r.ie<10||!n.data("isOutAnim")?c():setTimeout(function(){c()},200)}},r.closeAll=function(e,t){"function"==typeof e&&(t=e,e=null);var n=i("."+l[0]);i.each(n,function(a){var o=i(this),s=e?o.attr("type")===e:1;s&&r.close(o.attr("times"),a===n.length-1?t:null),s=null}),0===n.length&&"function"==typeof t&&t()};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(t){s=t.find(".layui-layer-input"),s.val(e.value||"").focus(),"function"==typeof f&&f(t)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n="layui-this",a=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,a="";if(e>0)for(a=''+t[0].title+"";i"+t[i].title+"";return a}(),content:'
            '+function(){var e=t.length,i=1,a="";if(e>0)for(a='
          • '+(t[0].content||"no content")+"
          • ";i'+(t[i].content||"no content")+"";return a}()+"
          ",success:function(t){var o=t.find(".layui-layer-title").children(),r=t.find(".layui-layer-tabmain").children();o.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var a=i(this),o=a.index();a.addClass(n).siblings().removeClass(n),r.eq(o).show().siblings().hide(),"function"==typeof e.change&&e.change(o)}),"function"==typeof a&&a(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=!("string"==typeof t.photos||t.photos instanceof i),f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){h();var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0)}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev(!0)}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext(!0)}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),a&&(t.anim=-1),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||'+function(){return u.length>1?'
          '+(u[d].alt||"")+""+s.imgIndex+" / "+u.length+"
          ":""}()+"",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
          是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.$),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){r.ready(),o.run(e.jQuery)}()}(window); -------------------------------------------------------------------------------- /src/main/resources/static/layer/mobile/layer.js: -------------------------------------------------------------------------------- 1 | /*! layer mobile-v2.0.0 Web 通用弹出层组件 MIT License */ 2 | ;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'

          '+(e?n.title[0]:n.title)+"

          ":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e=''+n.btn[0]+"",2===t&&(e=''+n.btn[1]+""+e),'
          '+e+"
          "):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='

          '+(n.content||"")+"

          "),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"
          ':"")+'
          "+l+'
          '+n.content+"
          "+c+"
          ",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;odiv{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px} -------------------------------------------------------------------------------- /src/main/resources/static/layer/theme/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/layer/theme/default/icon-ext.png -------------------------------------------------------------------------------- /src/main/resources/static/layer/theme/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/layer/theme/default/icon.png -------------------------------------------------------------------------------- /src/main/resources/static/layer/theme/default/layer.css: -------------------------------------------------------------------------------- 1 | .layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative;padding:20px}.layui-layer-content::-webkit-scrollbar-track{background-color:#f1f1f1;}.layui-layer-content::-webkit-scrollbar{width:10px;background-color:#f1f1f1;}.layui-layer-content::-webkit-scrollbar-thumb{background-color:#c1c1c1;}.layui-layer-border{border:0}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#fff;overflow:hidden;background-color:#293441;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:0;top:1px;width:12px;height:12px;margin-left:0;background-position:-155px -41px;*right:0;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-184px -41px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#293441;background-color:#293441;color:#fff;box-shadow:0 2px 5px rgba(0, 0, 0, 0.1) !important;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}.layui-layer-btn .layui-layer-btn1{color:#333;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:12px;left:15px;_left:-40px;width:20px;height:20px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border-radius:5px;box-shadow:rgba(0, 0, 0, 0.2) 0px 1px 6px}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:10px 40px 10px 45px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} -------------------------------------------------------------------------------- /src/main/resources/static/layer/theme/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/layer/theme/default/loading-0.gif -------------------------------------------------------------------------------- /src/main/resources/static/layer/theme/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/layer/theme/default/loading-1.gif -------------------------------------------------------------------------------- /src/main/resources/static/layer/theme/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rawchen/ShortUrl/2082debe4526023739a29baf28a56f07e63f6ef5/src/main/resources/static/layer/theme/default/loading-2.gif -------------------------------------------------------------------------------- /src/main/resources/templates/400.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ShortUrl 13 | 14 | 15 |
          16 |
          17 |
          18 |
          请求速度过快
          19 |
          20 |
          21 |
          22 |

          Requests are too frequent.

          23 |

          5s 后重定向到

          24 |
          25 | 26 |
          27 |
          28 |
          29 | 30 | 46 | -------------------------------------------------------------------------------- /src/main/resources/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ShortUrl 13 | 14 | 15 |
          16 |
          17 |
          18 |
          短链不存在
          19 |
          20 |
          21 |
          22 |

          Short link doesn't exist.

          23 |

          5s 后重定向到

          24 |
          25 | 26 |
          27 |
          28 |
          29 | 30 | 46 | -------------------------------------------------------------------------------- /src/main/resources/templates/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ShortUrl 13 | 14 | 15 |
          16 |
          17 |
          18 |
          404
          19 |
          20 |
          21 |
          22 |

          Page not found.

          23 |

          5s 后重定向到

          24 |
          25 | 26 |
          27 |
          28 |
          29 | 30 | 46 | -------------------------------------------------------------------------------- /src/main/resources/templates/error/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ShortUrl 13 | 14 | 15 |
          16 |
          17 |
          18 |
          500
          19 |
          20 |
          21 |
          22 |

          Internal server error.

          23 |

          5s 后重定向到

          24 |
          25 | 26 |
          27 |
          28 |
          29 | 30 | 46 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ShortUrl 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 |
          29 | 41 |
          42 | 43 | 44 | 45 |
          46 |
          47 |
          48 |
          49 |
          50 |

          免费缩短网址

          51 |
          专业社群营销、短信营销、互联网推广工具
          52 |
          工具特色
          53 |
            54 |
          • 域名简单
          • 55 |
          • 网址切换
          • 56 |
          • 随机网址
          • 57 |
          • 有效时间
          • 58 |
          • 密码安全
          • 59 |
          • 网址分组
          • 60 |
          • 智能定向
          • 61 |
          • 接口限流
          • 62 |
          • 生成二维码
          • 63 |
          • 数据统计
          • 64 |
          • 网址检测
          • 65 |
          • API接口
          • 66 |
          67 |
          68 |
          69 |
          70 |

          网址缩短

          71 |
          72 |
          73 |
          74 |
          75 |
          76 |
          77 |
          78 |
          79 |
          80 |
          81 |
          82 |
          83 |
          84 | 85 | 86 |
          87 |
          88 |
          89 | 90 |
          91 |
          92 |
          93 |
          94 |
          95 |
          96 |

          短网址有效期

          97 |
          98 | 99 | 100 |
          101 |
          102 |
          103 |

          访问密码

          104 |
          105 | 106 | 107 |
          108 |
          109 |
          110 |
          111 |
          112 |
          113 |
          114 | 115 | 116 | 117 |
          118 |
          119 |
          120 |
          121 |
          122 |
          123 |

          从不止于链接缩短,一个专业的营销推广工具

          124 |

          助力社群推广、短信推广、线上媒体推广等领域内有效提升推广效果

          125 |
          126 |
          127 |
          128 |

          域名简单

          129 |

          网址切换

          130 |

          随机网址

          131 |

          有效时间

          132 |

          密码安全

          133 |

          网址分组

          134 |

          智能定向

          135 |

          接口限流

          136 |

          生成二维码

          137 |

          数据统计

          138 |

          网址检测

          139 |

          API接口

          140 |
          141 |
          142 |

          智能定向,一个短网址多个推广链接

          143 |

          在不同的地区、设备、浏览器等显示不同的页面,使用定向功能,将不同用户导向不同的最终页面,满足您多维度的推广需求。

          144 |

          可修改原链接,灵活便捷

          145 |

          对于已经生成的短网址,如果原链接有变化,目前在推广的短网址不便于重新生成,您可以进行原链接的替换,短网址不变。

          146 |
          147 |
          148 |
          149 |

          专业的高级数据分析,帮您深入了解用户

          150 |

          报表显示访问数据,包含用户访问量、访问机型、地理分布、浏览器等数据一应俱全,让您精准分析用户。

          151 |
          152 |
          153 |
          154 |
          155 |
          156 |
          157 |

          场景应用

          158 |

          满足多种应用场景,实时分析渠道推广效果

          159 |
          160 |
          161 |
          162 |
          163 |

          短信营销

          164 |

          跳转快速稳定,提高用户体验和效果

          165 |

          减少字数成本,精准为您提供专业的营销推广统计报表数据,多台服务器保障全国各个地区极速跳转访问,降低无法访问的几率,为您的企业保驾护航。

          166 |
          167 |
          168 |
          169 |
          170 |

          社群推广

          171 |

          防误拦截屏蔽,保障推广内容有效性

          172 |

          根据公司产品生成短网址,设置各个渠道多平台投放,有效减少社群建立环节的用户流失。主动选择匹配属性,加入正确社群,降低推广复杂度并提升操作步骤。

          173 |
          174 |
          175 |
          176 |
          177 |

          产品运营

          178 |

          全国连通性高,全国各地正常访问

          179 |

          根据不同性别的用户、年龄、地区智能跳转到对应的推广页面,极大的提升产品的推广效果。生成不同的短链接,实现多个渠道的实时统计数据及推广报表。

          180 |
          181 |
          182 |
          183 |
          184 |
          185 |
          186 |
          187 |
          188 |
          189 | 192 | 195 |
          196 |
          197 |
          198 |
          199 | 210 |
          211 | 212 | 213 | 217 | 218 | -------------------------------------------------------------------------------- /src/main/resources/templates/password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ShortUrl 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
          23 |
          24 |
          25 |
          26 |

          请输入访问密码

          27 |
          28 | 29 | 30 | 31 |
          32 | 33 |
          34 |
          35 |
          36 |
          37 | 38 | 39 | 80 | -------------------------------------------------------------------------------- /src/test/java/com/rawchen/shorturl/ShortUrlApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.rawchen.shorturl; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ShortUrlApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------