├── .gitignore ├── src ├── main │ ├── resources │ │ ├── static │ │ │ ├── layer │ │ │ │ ├── skin │ │ │ │ │ ├── default │ │ │ │ │ │ ├── icon.png │ │ │ │ │ │ ├── icon-ext.png │ │ │ │ │ │ ├── loading-0.gif │ │ │ │ │ │ ├── loading-1.gif │ │ │ │ │ │ └── loading-2.gif │ │ │ │ │ └── layer.css │ │ │ │ └── layer.js │ │ │ ├── base │ │ │ │ ├── fonts │ │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ │ ├── css │ │ │ │ │ └── bootstrap-theme.min.css │ │ │ │ └── js │ │ │ │ │ ├── holder.min.js │ │ │ │ │ └── bootstrap.min.js │ │ │ └── css │ │ │ │ └── dashboard.css │ │ ├── mapper │ │ │ ├── user-mapper.xml │ │ │ └── module-mapper.xml │ │ ├── templates │ │ │ ├── unauthor.html │ │ │ ├── login.html │ │ │ ├── reports.html │ │ │ └── index.html │ │ ├── application.properties │ │ ├── logback.xml │ │ └── init-sql │ │ │ └── schema.sql │ └── java │ │ └── org │ │ └── jdonee │ │ └── cooking │ │ ├── mapper │ │ ├── UserMapper.java │ │ └── ModuleMapper.java │ │ ├── service │ │ ├── ModuleService.java │ │ ├── UserService.java │ │ ├── ModuleServiceImpl.java │ │ └── UserServiceImpl.java │ │ ├── domain │ │ ├── UserInfo.java │ │ └── ModuleInfo.java │ │ ├── web │ │ ├── IndexController.java │ │ └── LoginController.java │ │ ├── config │ │ ├── shiro │ │ │ ├── ShrioRedisCacheManager.java │ │ │ ├── URLPermissionsFilter.java │ │ │ ├── UserRealm.java │ │ │ ├── ShrioRedisCache.java │ │ │ └── ShiroConfig.java │ │ ├── redis │ │ │ ├── MyRedisProperties.java │ │ │ └── SecondaryRedisConfig.java │ │ ├── DruidConfig.java │ │ └── MvcConfig.java │ │ ├── ShiroRedisExampleBoot.java │ │ └── utils │ │ └── SerializeUtils.java └── test │ └── java │ └── org │ └── jdonee │ └── cooking │ └── ShiroRedisExampleBootTests.java ├── README.md ├── gradlew.bat └── gradlew /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /.settings/ 3 | /.project 4 | /.classpath 5 | /gradle/ 6 | /.springBeans 7 | /.gradle/ 8 | /build/ 9 | -------------------------------------------------------------------------------- /src/main/resources/static/layer/skin/default/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/layer/skin/default/icon.png -------------------------------------------------------------------------------- /src/main/resources/static/layer/skin/default/icon-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/layer/skin/default/icon-ext.png -------------------------------------------------------------------------------- /src/main/resources/static/layer/skin/default/loading-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/layer/skin/default/loading-0.gif -------------------------------------------------------------------------------- /src/main/resources/static/layer/skin/default/loading-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/layer/skin/default/loading-1.gif -------------------------------------------------------------------------------- /src/main/resources/static/layer/skin/default/loading-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/layer/skin/default/loading-2.gif -------------------------------------------------------------------------------- /src/main/resources/static/base/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/base/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/main/resources/static/base/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/base/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/main/resources/static/base/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/base/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/main/resources/static/base/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jdonee/Spring-boot-shiro-spring-session-redis-example/HEAD/src/main/resources/static/base/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /src/main/resources/mapper/user-mapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.mapper; 2 | 3 | import org.apache.ibatis.annotations.Select; 4 | import org.jdonee.cooking.domain.UserInfo; 5 | 6 | public interface UserMapper { 7 | 8 | @Select("select *from t_user where account=#{account}") 9 | UserInfo findByAccount(String account); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/service/ModuleService.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.service; 2 | 3 | import java.util.List; 4 | 5 | import org.jdonee.cooking.domain.ModuleInfo; 6 | 7 | public interface ModuleService { 8 | /** 9 | * 获取角色模块 10 | * 11 | * @param userId 12 | * @return 13 | */ 14 | List findModuleByUserId(int userId); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/domain/UserInfo.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.domain; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class UserInfo implements Serializable { 10 | 11 | private static final long serialVersionUID = -2736075850489736894L; 12 | 13 | private int id; 14 | private String account; 15 | private String password; 16 | private String name; 17 | private Date createTime; 18 | 19 | } -------------------------------------------------------------------------------- /src/main/resources/mapper/module-mapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/mapper/ModuleMapper.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Select; 6 | import org.jdonee.cooking.domain.ModuleInfo; 7 | 8 | public interface ModuleMapper { 9 | 10 | /** 11 | * 获取该人的权限模块 12 | * 13 | * @param userId 14 | * @return 15 | */ 16 | @Select(value = "select e.*from t_user_role b left join t_role c on b.role_id=c.id left join t_role_module d on c.id=d.role_id left join t_module e on d.module_id=e.id where b.user_id=#{userId}") 17 | List findModuleByUserId(int userId); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/domain/ModuleInfo.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.domain; 2 | 3 | import java.io.Serializable; 4 | import java.util.Date; 5 | 6 | import lombok.Data; 7 | 8 | @Data 9 | public class ModuleInfo implements Serializable { 10 | 11 | private static final long serialVersionUID = 2354275897681109437L; 12 | 13 | /** 路径 */ 14 | public static final int URL_TYPE = 1; 15 | /** 功能点 */ 16 | public static final int FUNCTION_TYPE = 2; 17 | 18 | private int id; 19 | private String moduleName; 20 | private String modulePath; 21 | private int moduleType; 22 | private String moduleKey; 23 | private Date createTime; 24 | } -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/service/UserService.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.service; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | 6 | import org.jdonee.cooking.domain.UserInfo; 7 | 8 | public interface UserService { 9 | 10 | /** 11 | * 根据账号Account查询当前用户 12 | * 13 | * @param account 14 | * @return 15 | */ 16 | UserInfo findByAccount(String account); 17 | 18 | /** 19 | * 获取资源集合 20 | * 21 | * @param account 22 | * @return 23 | */ 24 | Set findPermissions(String account); 25 | 26 | /** 27 | * 获取URL权限 28 | * 29 | * @param account 30 | * @return 31 | */ 32 | List findPermissionUrl(String account); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/service/ModuleServiceImpl.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.service; 2 | 3 | import java.util.List; 4 | 5 | import org.jdonee.cooking.domain.ModuleInfo; 6 | import org.jdonee.cooking.mapper.ModuleMapper; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public class ModuleServiceImpl implements ModuleService { 12 | 13 | @Autowired 14 | private ModuleMapper moduleMapper; 15 | 16 | /** 17 | * 获取角色模块 18 | * 19 | * @param userId 20 | * @return 21 | */ 22 | @Override 23 | public List findModuleByUserId(int userId) { 24 | return moduleMapper.findModuleByUserId(userId); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/web/IndexController.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.web; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class IndexController { 8 | 9 | /** 10 | * Go Index 11 | * 12 | * @return 13 | */ 14 | @RequestMapping(value = { "", "/", "index" }) 15 | public String index() { 16 | return "index"; 17 | } 18 | 19 | /** 20 | * unauthor 21 | * 22 | * @return 23 | */ 24 | @RequestMapping("unauthor") 25 | public String unauthor() { 26 | return "unauthor"; 27 | } 28 | 29 | /** 30 | * reports 31 | * 32 | * @return 33 | */ 34 | @RequestMapping("reports") 35 | public String reports() { 36 | return "reports"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/shiro/ShrioRedisCacheManager.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.shiro; 2 | 3 | import org.apache.shiro.cache.AbstractCacheManager; 4 | import org.apache.shiro.cache.Cache; 5 | import org.apache.shiro.cache.CacheException; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | 8 | public class ShrioRedisCacheManager extends AbstractCacheManager { 9 | 10 | private RedisTemplate shiroRedisTemplate; 11 | 12 | public ShrioRedisCacheManager(RedisTemplate shiroRedisTemplate) { 13 | this.shiroRedisTemplate = shiroRedisTemplate; 14 | } 15 | 16 | @Override 17 | protected Cache createCache(String name) throws CacheException { 18 | return new ShrioRedisCache(shiroRedisTemplate, name); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/templates/unauthor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 首页 8 | 9 | 10 | 11 | 15 | 16 | 17 |

Unauthorized!

18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring-boot-shiro-spring-session-redis-example 2 | * [spring-boot](http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/) 3 | * [spring-session](http://projects.spring.io/spring-session/) 4 | * [mybatis](https://github.com/mybatis/spring-boot-starter) 5 | * [druid](https://github.com/alibaba/druid) 6 | * [shiro](http://shiro.apache.org/) 7 | * [redis](http://redis.io/) 8 | * [jedis](https://github.com/xetorthio/jedis) 9 | * [lombok](https://projectlombok.org/) 10 | * [thymeleaf](http://www.thymeleaf.org/) 11 | 12 | > * 项目启动后输入:http://localhost:8080/ 13 | > * 该项目中, 增加了对url的拦截[URLPermissionsFilter](https://github.com/leelance/spring-boot-all/blob/master/spring-boot-shiro/src/main/java/com/lance/shiro/config/URLPermissionsFilter.java), 14 | > * 用admin/123456,拥有index权限reports未任何权限, jdonee/123456尚未分配任何权限. 15 | > * 参考[schema.sql](https://github.com/leelance/spring-boot-all/blob/master/spring-boot-shiro/src/main/resources/init-sql/schema.sql) 16 | > * shiro Cache交于Redis进行管理 17 | > * shiro Session交于Spring Session进行管理 18 | > * shiro 全面Java Config化,杜绝xml配置。 19 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/ShiroRedisExampleBoot.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking; 2 | 3 | import org.mybatis.spring.annotation.MapperScan; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.boot.web.support.SpringBootServletInitializer; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; 11 | 12 | @SpringBootApplication 13 | @MapperScan("org.jdonee.cooking.mapper") 14 | public class ShiroRedisExampleBoot extends SpringBootServletInitializer { 15 | 16 | /** 17 | * 增加Shiro模板引擎 18 | * 19 | * @return 20 | */ 21 | @Bean 22 | public ShiroDialect conditionalSecurityDialect() { 23 | return new ShiroDialect(); 24 | } 25 | 26 | @Override 27 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 28 | return application.sources(ShiroRedisExampleBoot.class); 29 | } 30 | 31 | public static void main(String[] args) { 32 | SpringApplication.run(ShiroRedisExampleBoot.class, args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/org/jdonee/cooking/ShiroRedisExampleBootTests.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking; 2 | 3 | //@RunWith(SpringRunner.class) 4 | //@SpringBootTest 5 | public class ShiroRedisExampleBootTests { 6 | 7 | // @Test 8 | // public void sessionExpiry() throws Exception { 9 | // 10 | // String port = null; 11 | // 12 | // try { 13 | // ConfigurableApplicationContext context = new SpringApplicationBuilder().sources(ShiroRedisExampleBoot.class) 14 | // .properties("server.port:0").initializers(new ServerPortInfoApplicationContextInitializer()).run(); 15 | // port = context.getEnvironment().getProperty("local.server.port"); 16 | // } catch (RuntimeException ex) { 17 | // if (!redisServerRunning(ex)) { 18 | // return; 19 | // } 20 | // throw ex; 21 | // } 22 | // 23 | // URI uri = URI.create("http://localhost:" + port + "/"); 24 | // RestTemplate restTemplate = new RestTemplate(); 25 | // 26 | // ResponseEntity response = restTemplate.getForEntity(uri, String.class); 27 | // String uuid1 = response.getBody(); 28 | // HttpHeaders requestHeaders = new HttpHeaders(); 29 | // requestHeaders.set("Cookie", response.getHeaders().getFirst("Set-Cookie")); 30 | // 31 | // RequestEntity request = new RequestEntity(requestHeaders, HttpMethod.GET, uri); 32 | // 33 | // String uuid2 = restTemplate.exchange(request, String.class).getBody(); 34 | // assertThat(uuid1).isEqualTo(uuid2); 35 | // 36 | // Thread.sleep(5000); 37 | // 38 | // String uuid3 = restTemplate.exchange(request, String.class).getBody(); 39 | // assertThat(uuid2).isNotEqualTo(uuid3); 40 | // } 41 | // 42 | // private boolean redisServerRunning(Throwable ex) { 43 | // if (ex instanceof RedisConnectionFailureException) { 44 | // return false; 45 | // } 46 | // return ex.getCause() == null || redisServerRunning(ex.getCause()); 47 | // } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/web/LoginController.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.web; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import org.apache.shiro.SecurityUtils; 6 | import org.apache.shiro.authc.AuthenticationException; 7 | import org.apache.shiro.authc.UsernamePasswordToken; 8 | import org.apache.shiro.subject.Subject; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 13 | 14 | @Controller 15 | public class LoginController { 16 | 17 | /** 18 | * Go login.html 19 | * 20 | * @return 21 | */ 22 | @RequestMapping(value = "login", method = RequestMethod.GET) 23 | public String login() { 24 | return "login"; 25 | } 26 | 27 | /** 28 | * Go login 29 | * 30 | * @param request 31 | * @return 32 | */ 33 | @RequestMapping(value = "login", method = RequestMethod.POST) 34 | public String login(HttpServletRequest request, RedirectAttributes rediect) { 35 | String account = request.getParameter("account"); 36 | String password = request.getParameter("password"); 37 | 38 | UsernamePasswordToken upt = new UsernamePasswordToken(account, password); 39 | Subject subject = SecurityUtils.getSubject(); 40 | try { 41 | subject.login(upt); 42 | } catch (AuthenticationException e) { 43 | e.printStackTrace(); 44 | rediect.addFlashAttribute("errorText", "您的账号或密码输入错误!"); 45 | return "redirect:/login"; 46 | } 47 | return "redirect:/index"; 48 | } 49 | 50 | /** 51 | * Exit 52 | * 53 | * @return 54 | */ 55 | @RequestMapping("logout") 56 | public String logout() { 57 | Subject subject = SecurityUtils.getSubject(); 58 | subject.logout(); 59 | return "redirect:/index"; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/service/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.service; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | 6 | import org.jdonee.cooking.domain.ModuleInfo; 7 | import org.jdonee.cooking.domain.UserInfo; 8 | import org.jdonee.cooking.mapper.UserMapper; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import com.google.common.collect.Lists; 13 | import com.google.common.collect.Sets; 14 | 15 | @Service 16 | public class UserServiceImpl implements UserService { 17 | 18 | @Autowired 19 | private UserMapper userMapper; 20 | 21 | @Autowired 22 | private ModuleService moduleService; 23 | 24 | /** 25 | * 根据账号Account查询当前用户 26 | * 27 | * @param account 28 | * @return 29 | */ 30 | @Override 31 | public UserInfo findByAccount(String account) { 32 | return userMapper.findByAccount(account); 33 | } 34 | 35 | /** 36 | * 获取资源集合 37 | * 38 | * @param account 39 | * @return 40 | */ 41 | @Override 42 | public Set findPermissions(String account) { 43 | Set set = Sets.newHashSet(); 44 | UserInfo user = findByAccount(account); 45 | List modules = moduleService.findModuleByUserId(user.getId()); 46 | 47 | for (ModuleInfo info : modules) { 48 | set.add(info.getModuleKey()); 49 | } 50 | return set; 51 | } 52 | 53 | /** 54 | * 获取URL权限 55 | * 56 | * @param account 57 | * @return 58 | */ 59 | @Override 60 | public List findPermissionUrl(String account) { 61 | List list = Lists.newArrayList(); 62 | UserInfo user = findByAccount(account); 63 | List modules = moduleService.findModuleByUserId(user.getId()); 64 | 65 | for (ModuleInfo info : modules) { 66 | if (info.getModuleType() == ModuleInfo.URL_TYPE) { 67 | list.add(info.getModulePath()); 68 | } 69 | } 70 | return list; 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/shiro/URLPermissionsFilter.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.shiro; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | 6 | import javax.servlet.ServletRequest; 7 | import javax.servlet.ServletResponse; 8 | import javax.servlet.http.HttpServletRequest; 9 | 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.apache.shiro.SecurityUtils; 12 | import org.apache.shiro.subject.Subject; 13 | import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter; 14 | import org.jdonee.cooking.service.UserService; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Component; 17 | 18 | @Component 19 | public class URLPermissionsFilter extends PermissionsAuthorizationFilter { 20 | 21 | @Autowired 22 | private UserService userService; 23 | 24 | @Override 25 | public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) 26 | throws IOException { 27 | String curUrl = getRequestUrl(request); 28 | Subject subject = SecurityUtils.getSubject(); 29 | if (subject.getPrincipal() == null || StringUtils.endsWithAny(curUrl, ".js", ".css", ".html") 30 | || StringUtils.endsWithAny(curUrl, ".jpg", ".png", ".gif", ".jpeg") 31 | || StringUtils.equals(curUrl, "/unauthor")) { 32 | return true; 33 | } 34 | List urls = userService.findPermissionUrl(subject.getPrincipal().toString()); 35 | return urls.contains(curUrl); 36 | } 37 | 38 | /** 39 | * 获取当前URL+Parameter 40 | * 41 | * @author lance 42 | * @since 2014年12月18日 下午3:09:26 43 | * @param request 拦截请求request 44 | * @return 返回完整URL 45 | */ 46 | private String getRequestUrl(ServletRequest request) { 47 | HttpServletRequest req = (HttpServletRequest) request; 48 | String queryString = req.getQueryString(); 49 | 50 | queryString = StringUtils.isBlank(queryString) ? "" : "?" + queryString; 51 | return req.getRequestURI() + queryString; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/resources/static/css/dashboard.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | /* 3 | * Base structure 4 | */ 5 | 6 | /* Move down content because we have a fixed navbar that is 50px tall */ 7 | body { 8 | padding-top: 50px; 9 | } 10 | 11 | 12 | /* 13 | * Global add-ons 14 | */ 15 | 16 | .sub-header { 17 | padding-bottom: 10px; 18 | border-bottom: 1px solid #eee; 19 | } 20 | 21 | /* 22 | * Top navigation 23 | * Hide default border to remove 1px line. 24 | */ 25 | .navbar-fixed-top { 26 | border: 0; 27 | } 28 | 29 | /* 30 | * Sidebar 31 | */ 32 | 33 | /* Hide for mobile, show later */ 34 | .sidebar { 35 | display: none; 36 | } 37 | @media (min-width: 768px) { 38 | .sidebar { 39 | position: fixed; 40 | top: 41px; 41 | bottom: 0; 42 | left: 0; 43 | z-index: 1000; 44 | display: block; 45 | padding: 15px; 46 | overflow-x: hidden; 47 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ 48 | background-color: #f5f5f5; 49 | border-right: 1px solid #eee; 50 | } 51 | } 52 | 53 | /* Sidebar navigation */ 54 | .nav-sidebar { 55 | margin-right: -21px; /* 20px padding + 1px border */ 56 | margin-bottom: 20px; 57 | margin-left: -20px; 58 | } 59 | .nav-sidebar > li > a { 60 | padding-right: 20px; 61 | padding-left: 20px; 62 | } 63 | .nav-sidebar > .active > a, 64 | .nav-sidebar > .active > a:hover, 65 | .nav-sidebar > .active > a:focus { 66 | color: #fff; 67 | background-color: #428bca; 68 | } 69 | 70 | 71 | /* 72 | * Main content 73 | */ 74 | 75 | .main { 76 | padding: 20px; 77 | } 78 | @media (min-width: 768px) { 79 | .main { 80 | padding-right: 40px; 81 | padding-left: 40px; 82 | } 83 | } 84 | .main .page-header { 85 | margin-top: 0; 86 | } 87 | 88 | 89 | /* 90 | * Placeholder dashboard ideas 91 | */ 92 | 93 | .placeholders { 94 | margin-bottom: 30px; 95 | text-align: center; 96 | } 97 | .placeholders h4 { 98 | margin-bottom: 0; 99 | } 100 | .placeholder { 101 | margin-bottom: 20px; 102 | } 103 | .placeholder img { 104 | display: inline-block; 105 | border-radius: 50%; 106 | } -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/shiro/UserRealm.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.shiro; 2 | 3 | import org.apache.shiro.authc.AuthenticationException; 4 | import org.apache.shiro.authc.AuthenticationInfo; 5 | import org.apache.shiro.authc.AuthenticationToken; 6 | import org.apache.shiro.authc.SimpleAuthenticationInfo; 7 | import org.apache.shiro.authc.UnknownAccountException; 8 | import org.apache.shiro.authc.UsernamePasswordToken; 9 | import org.apache.shiro.authc.credential.HashedCredentialsMatcher; 10 | import org.apache.shiro.authz.AuthorizationInfo; 11 | import org.apache.shiro.authz.SimpleAuthorizationInfo; 12 | import org.apache.shiro.realm.AuthorizingRealm; 13 | import org.apache.shiro.subject.PrincipalCollection; 14 | import org.jdonee.cooking.domain.UserInfo; 15 | import org.jdonee.cooking.service.UserService; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Component; 18 | 19 | /** 20 | * 验证用户登录 21 | * 22 | * @author Administrator 23 | */ 24 | @Component("userRealm") 25 | public class UserRealm extends AuthorizingRealm { 26 | 27 | @Autowired 28 | private UserService userService; 29 | 30 | public UserRealm() { 31 | setName("UserRealm"); 32 | // 采用MD5加密 33 | setCredentialsMatcher(new HashedCredentialsMatcher("md5")); 34 | } 35 | 36 | // 权限资源角色 37 | @Override 38 | protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 39 | String username = (String) principals.getPrimaryPrincipal(); 40 | SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 41 | // add Permission Resources 42 | info.setStringPermissions(userService.findPermissions(username)); 43 | // add Roles String[Set roles] 44 | // info.setRoles(roles); 45 | return info; 46 | } 47 | 48 | // 登录验证 49 | @Override 50 | protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 51 | UsernamePasswordToken upt = (UsernamePasswordToken) token; 52 | String userName = upt.getUsername(); 53 | UserInfo user = userService.findByAccount(userName); 54 | if (user == null) { 55 | throw new UnknownAccountException(); 56 | } 57 | SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userName, user.getPassword(), getName()); 58 | return info; 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/utils/SerializeUtils.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.utils; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.ObjectInputStream; 6 | import java.io.ObjectOutputStream; 7 | import java.io.Serializable; 8 | 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | @Slf4j 12 | public final class SerializeUtils { 13 | 14 | /** 15 | * deserialize 16 | * 17 | * @param bytes 18 | * @return 19 | */ 20 | public static Object deserialize(byte[] bytes) { 21 | Object result = null; 22 | if (isEmpty(bytes)) { 23 | return null; 24 | } 25 | try { 26 | ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); 27 | try { 28 | ObjectInputStream objectInputStream = new ObjectInputStream(byteStream); 29 | try { 30 | result = objectInputStream.readObject(); 31 | } catch (ClassNotFoundException ex) { 32 | throw new Exception("Failed to deserialize object type", ex); 33 | } 34 | } catch (Throwable ex) { 35 | throw new Exception("Failed to deserialize", ex); 36 | } 37 | } catch (Exception e) { 38 | log.error("Failed to deserialize", e); 39 | } 40 | return result; 41 | } 42 | 43 | public static boolean isEmpty(byte[] data) { 44 | return data == null || data.length == 0; 45 | } 46 | 47 | /** 48 | * serialize 49 | * 50 | * @param object 51 | * @return 52 | */ 53 | public static byte[] serialize(Object object) { 54 | byte[] result = null; 55 | if (object == null) { 56 | return new byte[0]; 57 | } 58 | try { 59 | ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128); 60 | try { 61 | if (!(object instanceof Serializable)) { 62 | throw new IllegalArgumentException( 63 | SerializeUtils.class.getSimpleName() + " requires a Serializable payload " 64 | + "but received an object of type [" + object.getClass().getName() + "]"); 65 | } 66 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream); 67 | objectOutputStream.writeObject(object); 68 | objectOutputStream.flush(); 69 | result = byteStream.toByteArray(); 70 | } catch (Throwable ex) { 71 | throw new Exception("Failed to serialize", ex); 72 | } 73 | } catch (Exception ex) { 74 | log.error("Failed to serialize", ex); 75 | } 76 | return result; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # set to false for hot refresh 2 | spring.thymeleaf.cache=false 3 | spring.thymeleaf.mode=HTML 4 | 5 | #custom set 6 | spring.main.show_banner=false 7 | server.compression.enabled=true 8 | server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript 9 | 10 | # REDIS (RedisProperties) 11 | spring.redis.database=10 12 | spring.redis.secondary-database=11 13 | spring.redis.host=127.0.0.1 14 | spring.redis.password=1qazse4 15 | spring.redis.port=6379 16 | spring.redis.timeout=0 17 | spring.redis.pool.max-active=8 18 | spring.redis.pool.max-total=50 19 | spring.redis.pool.max-wait-millis=15000 20 | spring.redis.pool.test-on-borrow=true 21 | spring.redis.pool.max-idle=10 22 | spring.redis.pool.max-wait=-1 23 | spring.redis.pool.min-idle=0 24 | #session\u8fc7\u671f 25 | spring.redis.session-expire=1800 26 | 27 | #MYBATIS 28 | mybatis.type-aliases-package=org.jdonee.cooking.domain 29 | mybatis.mapper-locations=classpath*:/mapper/*_mapper.xml 30 | mybatis.configuration.map-underscore-to-camel-case=true 31 | mybatis.configuration.use-generated-keys=true 32 | mybatis.configuration.default-fetch-size=100 33 | mybatis.configuration.default-statement-timeout=30 34 | 35 | #DATASOURCE 36 | spring.datasource.schema=classpath:init-sql/schema.sql 37 | spring.datasource.continueOnError=true 38 | 39 | spring.datasource.url=jdbc:mysql://localhost/demo-schema 40 | spring.datasource.username=root 41 | spring.datasource.password=root 42 | spring.datasource.driverClass=com.mysql.jdbc.Driver 43 | 44 | #druid console 45 | druid.loginUsername=admin 46 | druid.loginPassword=123456 47 | druid.resetEnable=false 48 | 49 | #DRUID-DATASOURCE 50 | spring.datasource.initialSize=5 51 | spring.datasource.minIdle=5 52 | spring.datasource.maxActive=20 53 | spring.datasource.maxWait=60000 54 | spring.datasource.timeBetweenEvictionRunsMillis=60000 55 | spring.datasource.minEvictableIdleTimeMillis=300000 56 | spring.datasource.validationQuery=select 'x' 57 | spring.datasource.testWhileIdle=true 58 | spring.datasource.testOnBorrow=false 59 | spring.datasource.testOnReturn=false 60 | spring.datasource.poolPreparedStatements=true 61 | spring.datasource.maxOpenPreparedStatements=20 62 | spring.datasource.filters=stat,wall 63 | spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/redis/MyRedisProperties.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.redis; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import lombok.Data; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | import lombok.Setter; 10 | 11 | @Data 12 | @Configuration 13 | @NoArgsConstructor 14 | @ConfigurationProperties(prefix = "spring.redis") 15 | public class MyRedisProperties { 16 | 17 | /** 18 | * Database index used by the connection factory. 19 | */ 20 | private int database = 0; 21 | 22 | private int secondaryDatabase = 1; 23 | 24 | /** 25 | * Redis url, which will overrule host, port and password if set. 26 | */ 27 | private String url; 28 | 29 | /** 30 | * Redis server host. 31 | */ 32 | private String host = "localhost"; 33 | 34 | /** 35 | * Login password of the redis server. 36 | */ 37 | private String password; 38 | 39 | /** 40 | * Redis server port. 41 | */ 42 | private int port = 6379; 43 | 44 | /** 45 | * Enable SSL. 46 | */ 47 | private boolean ssl; 48 | 49 | /** 50 | * Connection timeout in milliseconds. 51 | */ 52 | private int timeout; 53 | 54 | private int sessionExpire; 55 | 56 | private Pool pool; 57 | 58 | /** 59 | * Pool properties. 60 | */ 61 | @Getter 62 | @Setter 63 | public static class Pool { 64 | /** 65 | * Max number of "idle" connections in the pool. Use a negative value to indicate 66 | * an unlimited number of idle connections. 67 | */ 68 | private int maxIdle = 8; 69 | 70 | /** 71 | * Target for the minimum number of idle connections to maintain in the pool. This 72 | * setting only has an effect if it is positive. 73 | */ 74 | private int minIdle = 0; 75 | 76 | /** 77 | * Max number of connections that can be allocated by the pool at a given time. 78 | * Use a negative value for no limit. 79 | */ 80 | private int maxActive = 8; 81 | 82 | /** 83 | * Maximum amount of time (in milliseconds) a connection allocation should block 84 | * before throwing an exception when the pool is exhausted. Use a negative value 85 | * to block indefinitely. 86 | */ 87 | private int maxWait = -1; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | Login 9 | 10 | 11 | 12 | 13 | 14 | 18 | 65 | 66 | 67 |
68 | 81 |
82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | %date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 14 | 15 | 16 | 17 | 18 | ${log_dir}/info.log 19 | 20 | 21 | INFO 22 | ACCEPT 23 | DENY 24 | 25 | 26 | ${maxHistory} 27 | ${log_dir}/info.%d{yyyy-MM-dd}.log 28 | 29 | 30 | 31 | ${maxFileSize} 32 | 33 | 34 | %date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 35 | 36 | 37 | 38 | 39 | ${log_dir}/warn.log 40 | 41 | 42 | WARN 43 | ACCEPT 44 | DENY 45 | 46 | 47 | ${maxHistory} 48 | ${log_dir}/warn.%d{yyyy-MM-dd}.log 49 | 50 | 51 | 52 | ${maxFileSize} 53 | 54 | 55 | %date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/shiro/ShrioRedisCache.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.shiro; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | import org.apache.commons.collections.CollectionUtils; 10 | import org.apache.shiro.cache.Cache; 11 | import org.apache.shiro.cache.CacheException; 12 | import org.jdonee.cooking.utils.SerializeUtils; 13 | import org.springframework.data.redis.core.RedisTemplate; 14 | import org.springframework.data.redis.core.ValueOperations; 15 | 16 | import com.google.common.collect.Sets; 17 | 18 | import lombok.extern.slf4j.Slf4j; 19 | 20 | @Slf4j 21 | public class ShrioRedisCache implements Cache { 22 | private RedisTemplate shiroRedisTemplate; 23 | private String prefix = "shiro_redis:"; 24 | 25 | public ShrioRedisCache(RedisTemplate shiroRedisTemplate) { 26 | this.shiroRedisTemplate = shiroRedisTemplate; 27 | } 28 | 29 | public ShrioRedisCache(RedisTemplate shiroRedisTemplate, String prefix) { 30 | this(shiroRedisTemplate); 31 | this.prefix = prefix; 32 | } 33 | 34 | @Override 35 | public V get(K key) throws CacheException { 36 | if (log.isDebugEnabled()) { 37 | log.debug("Key: {}", key); 38 | } 39 | if (key == null) { 40 | return null; 41 | } 42 | 43 | byte[] bkey = getByteKey(key); 44 | return shiroRedisTemplate.opsForValue().get(bkey); 45 | } 46 | 47 | @Override 48 | public V put(K key, V value) throws CacheException { 49 | if (log.isDebugEnabled()) { 50 | log.debug("Key: {}, value: {}", key, value); 51 | } 52 | 53 | if (key == null || value == null) { 54 | return null; 55 | } 56 | 57 | byte[] bkey = getByteKey(key); 58 | shiroRedisTemplate.opsForValue().set(bkey, value); 59 | return value; 60 | } 61 | 62 | @Override 63 | public V remove(K key) throws CacheException { 64 | if (log.isDebugEnabled()) { 65 | log.debug("Key: {}", key); 66 | } 67 | 68 | if (key == null) { 69 | return null; 70 | } 71 | 72 | byte[] bkey = getByteKey(key); 73 | ValueOperations vo = shiroRedisTemplate.opsForValue(); 74 | V value = vo.get(bkey); 75 | shiroRedisTemplate.delete(bkey); 76 | return value; 77 | } 78 | 79 | @Override 80 | public void clear() throws CacheException { 81 | shiroRedisTemplate.getConnectionFactory().getConnection().flushDb(); 82 | } 83 | 84 | @Override 85 | public int size() { 86 | Long len = shiroRedisTemplate.getConnectionFactory().getConnection().dbSize(); 87 | return len.intValue(); 88 | } 89 | 90 | @SuppressWarnings("unchecked") 91 | @Override 92 | public Set keys() { 93 | byte[] bkey = (prefix + "*").getBytes(); 94 | Set set = shiroRedisTemplate.keys(bkey); 95 | Set result = Sets.newHashSet(); 96 | 97 | if (CollectionUtils.isEmpty(set)) { 98 | return Collections.emptySet(); 99 | } 100 | 101 | for (byte[] key : set) { 102 | result.add((K) key); 103 | } 104 | return result; 105 | } 106 | 107 | @Override 108 | public Collection values() { 109 | Set keys = keys(); 110 | List values = new ArrayList<>(keys.size()); 111 | for (K k : keys) { 112 | byte[] bkey = getByteKey(k); 113 | values.add(shiroRedisTemplate.opsForValue().get(bkey)); 114 | } 115 | return values; 116 | } 117 | 118 | private byte[] getByteKey(K key) { 119 | if (key instanceof String) { 120 | String preKey = this.prefix + key; 121 | return preKey.getBytes(); 122 | } else { 123 | return SerializeUtils.serialize(key); 124 | } 125 | } 126 | 127 | public String getPrefix() { 128 | return prefix; 129 | } 130 | 131 | public void setPrefix(String prefix) { 132 | this.prefix = prefix; 133 | } 134 | } -------------------------------------------------------------------------------- /src/main/resources/templates/reports.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Reports 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 44 | 45 |
46 |
47 | 63 |
64 |

Reports

65 |
66 |
67 |
68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/DruidConfig.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config; 2 | 3 | import java.sql.SQLException; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 9 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | import com.alibaba.druid.pool.DruidDataSource; 14 | import com.alibaba.druid.support.http.StatViewServlet; 15 | import com.alibaba.druid.support.http.WebStatFilter; 16 | 17 | import lombok.extern.slf4j.Slf4j; 18 | 19 | @Configuration 20 | @Slf4j 21 | public class DruidConfig { 22 | 23 | /** 24 | * 注册一个StatViewServlet 25 | * 26 | * @return 27 | */ 28 | @Bean 29 | public ServletRegistrationBean druidStatViewServlet(@Value("${druid.loginUsername}") String loginUsername, 30 | @Value("${druid.loginPassword}") String loginPassword, @Value("${druid.resetEnable}") String resetEnable) { 31 | // org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册. 32 | ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), 33 | "/druid/*"); 34 | // 添加初始化参数:initParams 35 | // 白名单: 36 | servletRegistrationBean.addInitParameter("allow", "127.0.0.1"); 37 | // IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page. 38 | servletRegistrationBean.addInitParameter("deny", "192.168.1.73"); 39 | // 登录查看信息的账号密码. 40 | servletRegistrationBean.addInitParameter("loginUsername", loginUsername); 41 | servletRegistrationBean.addInitParameter("loginPassword", loginPassword); 42 | // 是否能够重置数据. 43 | servletRegistrationBean.addInitParameter("resetEnable", resetEnable); 44 | return servletRegistrationBean; 45 | } 46 | 47 | /** 48 | * 注册一个:filterRegistrationBean 49 | * 50 | * @return 51 | */ 52 | @Bean 53 | public FilterRegistrationBean druidStatFilter() { 54 | FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); 55 | // 添加过滤规则. 56 | filterRegistrationBean.addUrlPatterns("/*"); 57 | // 添加不需要忽略的格式信息. 58 | filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); 59 | return filterRegistrationBean; 60 | } 61 | 62 | @Bean 63 | public DataSource druidDataSource(@Value("${spring.datasource.driverClass}") String driver, 64 | @Value("${spring.datasource.url}") String url, @Value("${spring.datasource.username}") String username, 65 | @Value("${spring.datasource.password}") String password, 66 | @Value("${spring.datasource.filters}") String filters, 67 | @Value("${spring.datasource.maxActive}") int maxActive, 68 | @Value("${spring.datasource.initialSize}") int initialSize, 69 | @Value("${spring.datasource.maxWait}") long maxWait, @Value("${spring.datasource.minIdle}") int minIdle, 70 | @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") int timeBetweenEvictionRunsMillis, 71 | @Value("${spring.datasource.minEvictableIdleTimeMillis}") long minEvictableIdleTimeMillis, 72 | @Value("${spring.datasource.validationQuery}") String validationQuery, 73 | @Value("${spring.datasource.testWhileIdle}") boolean testWhileIdle, 74 | @Value("${spring.datasource.testOnBorrow}") boolean testOnBorrow, 75 | @Value("${spring.datasource.testOnReturn}") boolean testOnReturn, 76 | @Value("${spring.datasource.poolPreparedStatements}") boolean poolPreparedStatements, 77 | @Value("${spring.datasource.maxOpenPreparedStatements}") int maxOpenPreparedStatements, 78 | @Value("${spring.datasource.connectionProperties}") String connectionProperties) { 79 | DruidDataSource druidDataSource = new DruidDataSource(); 80 | druidDataSource.setDriverClassName(driver); 81 | druidDataSource.setUrl(url); 82 | druidDataSource.setUsername(username); 83 | druidDataSource.setPassword(password); 84 | druidDataSource.setMaxActive(maxActive); 85 | druidDataSource.setInitialSize(initialSize); 86 | druidDataSource.setMaxWait(maxWait); 87 | druidDataSource.setMinIdle(minIdle); 88 | druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); 89 | druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); 90 | druidDataSource.setValidationQuery(validationQuery); 91 | druidDataSource.setTestWhileIdle(testWhileIdle); 92 | druidDataSource.setTestOnBorrow(testOnBorrow); 93 | druidDataSource.setTestOnReturn(testOnReturn); 94 | druidDataSource.setPoolPreparedStatements(poolPreparedStatements); 95 | druidDataSource.setMaxOpenPreparedStatements(maxOpenPreparedStatements); 96 | druidDataSource.setConnectionProperties(connectionProperties); 97 | try { 98 | druidDataSource.setFilters(filters);// 配置防火墙和统计插件 99 | } catch (SQLException e) { 100 | log.error(e.getMessage()); 101 | } 102 | return druidDataSource; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/resources/init-sql/schema.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Date: 2016-06-01 23:44:23 3 | */ 4 | 5 | SET FOREIGN_KEY_CHECKS=0; 6 | 7 | -- ---------------------------- 8 | -- Table structure for `t_module` 9 | -- ---------------------------- 10 | DROP TABLE IF EXISTS `t_module`; 11 | CREATE TABLE `t_module` ( 12 | `id` int(11) NOT NULL AUTO_INCREMENT, 13 | `module_name` varchar(32) DEFAULT NULL, 14 | `module_path` varchar(50) DEFAULT NULL, 15 | `module_type` int(2) DEFAULT NULL COMMENT '1.URL, 2.功能', 16 | `module_key` varchar(32) DEFAULT NULL, 17 | `create_time` datetime DEFAULT NULL, 18 | PRIMARY KEY (`id`) 19 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 20 | 21 | -- ---------------------------- 22 | -- Records of t_module 23 | -- ---------------------------- 24 | INSERT INTO `t_module` VALUES ('1', 'Overview', '/index', '1', 'IndexUrl', '2016-06-01 23:41:39'); 25 | INSERT INTO `t_module` VALUES ('2', 'Reports', null, '1', 'Reports', '2016-06-02 09:42:17'); 26 | INSERT INTO `t_module` VALUES ('3', 'Analytics', null, '1', 'Analytics', '2016-06-03 21:42:17'); 27 | INSERT INTO `t_module` VALUES ('4', 'Export', null, '1', 'Export', '2016-06-03 20:38:01'); 28 | INSERT INTO `t_module` VALUES ('5', 'Nav item', null, '1', 'Nav_item', '2016-06-03 20:38:04'); 29 | INSERT INTO `t_module` VALUES ('6', 'Nav item again', null, '1', 'Nav_item_again', '2016-06-03 20:38:08'); 30 | INSERT INTO `t_module` VALUES ('7', 'One more nav', null, '1', 'One_more_nav', '2016-06-21 20:38:11'); 31 | INSERT INTO `t_module` VALUES ('8', 'Another nav item', null, '1', 'Another_nav_item', '2016-05-29 20:38:23'); 32 | INSERT INTO `t_module` VALUES ('9', 'More navigation', null, '1', 'More_navigation', '2016-06-05 20:38:14'); 33 | INSERT INTO `t_module` VALUES ('10', 'Nav item again', null, '1', 'Nav_item_again1', '2016-07-01 20:38:28'); 34 | INSERT INTO `t_module` VALUES ('11', 'One more nav', null, '1', 'One_more_nav1', '2016-05-31 20:38:18'); 35 | INSERT INTO `t_module` VALUES ('12', 'Another nav item', null, '1', 'Another_nav_item1', '2016-05-29 20:38:31'); 36 | 37 | -- ---------------------------- 38 | -- Table structure for `t_role` 39 | -- ---------------------------- 40 | DROP TABLE IF EXISTS `t_role`; 41 | CREATE TABLE `t_role` ( 42 | `id` int(11) NOT NULL AUTO_INCREMENT, 43 | `role_name` varchar(32) DEFAULT NULL, 44 | `description` varchar(200) DEFAULT NULL, 45 | `create_time` datetime DEFAULT NULL, 46 | PRIMARY KEY (`id`) 47 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 48 | 49 | -- ---------------------------- 50 | -- Records of t_role 51 | -- ---------------------------- 52 | INSERT INTO `t_role` VALUES ('1', '管理员', '系统管理员', '2016-06-01 23:41:11'); 53 | 54 | -- ---------------------------- 55 | -- Table structure for `t_role_module` 56 | -- ---------------------------- 57 | DROP TABLE IF EXISTS `t_role_module`; 58 | CREATE TABLE `t_role_module` ( 59 | `id` int(11) NOT NULL AUTO_INCREMENT, 60 | `role_id` int(11) DEFAULT NULL, 61 | `module_id` int(11) DEFAULT NULL, 62 | PRIMARY KEY (`id`) 63 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 64 | 65 | -- ---------------------------- 66 | -- Records of t_role_module 67 | -- ---------------------------- 68 | INSERT INTO `t_role_module` VALUES ('1', '1', '1'); 69 | INSERT INTO `t_role_module` VALUES ('2', '1', '2'); 70 | INSERT INTO `t_role_module` VALUES ('3', '1', '3'); 71 | INSERT INTO `t_role_module` VALUES ('4', '1', '4'); 72 | INSERT INTO `t_role_module` VALUES ('5', '1', '5'); 73 | INSERT INTO `t_role_module` VALUES ('6', '1', '6'); 74 | INSERT INTO `t_role_module` VALUES ('7', '1', '7'); 75 | INSERT INTO `t_role_module` VALUES ('8', '1', '8'); 76 | INSERT INTO `t_role_module` VALUES ('9', '1', '9'); 77 | INSERT INTO `t_role_module` VALUES ('10', '1', '10'); 78 | INSERT INTO `t_role_module` VALUES ('11', '1', '11'); 79 | INSERT INTO `t_role_module` VALUES ('12', '1', '12'); 80 | 81 | -- ---------------------------- 82 | -- Table structure for `t_user` 83 | -- ---------------------------- 84 | DROP TABLE IF EXISTS `t_user`; 85 | CREATE TABLE `t_user` ( 86 | `id` int(11) NOT NULL AUTO_INCREMENT, 87 | `account` varchar(32) DEFAULT NULL, 88 | `password` varchar(32) DEFAULT NULL, 89 | `name` varchar(32) DEFAULT NULL, 90 | `create_time` datetime DEFAULT NULL, 91 | PRIMARY KEY (`id`) 92 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; 93 | 94 | -- ---------------------------- 95 | -- Records of t_user 96 | -- ---------------------------- 97 | INSERT INTO `t_user` VALUES ('2', 'jdonee', 'e10adc3949ba59abbe56e057f20f883e', 'Jdonee', '2016-06-02 23:35:38'); 98 | INSERT INTO `t_user` VALUES ('1', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 'Admin', '2016-06-01 23:35:17'); 99 | 100 | -- ---------------------------- 101 | -- Table structure for `t_user_role` 102 | -- ---------------------------- 103 | DROP TABLE IF EXISTS `t_user_role`; 104 | CREATE TABLE `t_user_role` ( 105 | `id` int(11) NOT NULL AUTO_INCREMENT, 106 | `user_id` int(11) DEFAULT NULL, 107 | `role_id` int(11) DEFAULT NULL, 108 | PRIMARY KEY (`id`) 109 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 110 | 111 | -- ---------------------------- 112 | -- Records of t_user_role 113 | -- ---------------------------- 114 | INSERT INTO `t_user_role` VALUES ('1', '1', '1'); 115 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/shiro/ShiroConfig.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.shiro; 2 | 3 | import java.util.Map; 4 | 5 | import javax.servlet.DispatcherType; 6 | import javax.servlet.Filter; 7 | 8 | import org.apache.shiro.spring.LifecycleBeanPostProcessor; 9 | import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 10 | import org.apache.shiro.web.filter.authc.AnonymousFilter; 11 | import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 12 | import org.apache.shiro.web.session.mgt.ServletContainerSessionManager; 13 | import org.jdonee.cooking.config.redis.MyRedisProperties; 14 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 15 | import org.springframework.context.annotation.Bean; 16 | import org.springframework.context.annotation.Configuration; 17 | import org.springframework.context.annotation.DependsOn; 18 | import org.springframework.context.annotation.Primary; 19 | import org.springframework.data.redis.connection.RedisConnectionFactory; 20 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 21 | import org.springframework.data.redis.core.RedisTemplate; 22 | import org.springframework.web.filter.DelegatingFilterProxy; 23 | 24 | import com.google.common.collect.Maps; 25 | 26 | import lombok.extern.slf4j.Slf4j; 27 | 28 | @Configuration 29 | @Slf4j 30 | public class ShiroConfig { 31 | 32 | /** 33 | * 加载属性文件数据 34 | * 35 | * @return 36 | */ 37 | @Bean 38 | public MyRedisProperties shiroProperties() { 39 | return new MyRedisProperties(); 40 | } 41 | 42 | /** 43 | * FilterRegistrationBean 44 | * 45 | * @return 46 | */ 47 | @Bean 48 | public FilterRegistrationBean filterRegistrationBean() { 49 | FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); 50 | filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); 51 | filterRegistration.setEnabled(true); 52 | filterRegistration.addUrlPatterns("/*"); 53 | filterRegistration.setDispatcherTypes(DispatcherType.REQUEST); 54 | return filterRegistration; 55 | } 56 | 57 | /** 58 | * @see org.apache.shiro.spring.web.ShiroFilterFactoryBean 59 | * @return 60 | */ 61 | @Bean(name = "shiroFilter") 62 | public ShiroFilterFactoryBean shiroFilter() { 63 | ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); 64 | bean.setSecurityManager(securityManager()); 65 | bean.setLoginUrl("/login"); 66 | bean.setUnauthorizedUrl("/unauthor"); 67 | 68 | Map filters = Maps.newHashMap(); 69 | filters.put("perms", urlPermissionsFilter()); 70 | filters.put("anon", new AnonymousFilter()); 71 | bean.setFilters(filters); 72 | 73 | Map chains = Maps.newHashMap(); 74 | chains.put("/druid/**", "anon"); 75 | chains.put("/login", "anon"); 76 | chains.put("/unauthor", "anon"); 77 | chains.put("/logout", "logout"); 78 | chains.put("/base/**", "anon"); 79 | chains.put("/css/**", "anon"); 80 | chains.put("/layer/**", "anon"); 81 | chains.put("/**", "authc,perms"); 82 | bean.setFilterChainDefinitionMap(chains); 83 | return bean; 84 | } 85 | 86 | /** 87 | * 权限管理器 88 | * 89 | * @return 90 | */ 91 | @Bean(name = "securityManager") 92 | public DefaultWebSecurityManager securityManager() { 93 | DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); 94 | // 数据库认证的实现 95 | manager.setRealm(userRealm()); 96 | // session 管理器 97 | manager.setSessionManager(sessionManager()); 98 | // 缓存管理器 99 | manager.setCacheManager(redisCacheManager()); 100 | return manager; 101 | } 102 | 103 | /** 104 | * DefaultWebSessionManager 105 | * 106 | * @return 107 | */ 108 | @Bean(name = "sessionManager") 109 | public ServletContainerSessionManager sessionManager() { 110 | ServletContainerSessionManager sessionManager = new ServletContainerSessionManager(); 111 | return sessionManager; 112 | } 113 | 114 | /** 115 | * @see UserRealm--->AuthorizingRealm 116 | * @return 117 | */ 118 | @Bean 119 | @DependsOn(value = { "lifecycleBeanPostProcessor", "shrioRedisCacheManager" }) 120 | public UserRealm userRealm() { 121 | UserRealm userRealm = new UserRealm(); 122 | userRealm.setCacheManager(redisCacheManager()); 123 | userRealm.setCachingEnabled(true); 124 | userRealm.setAuthenticationCachingEnabled(false);//禁用认证缓存 125 | userRealm.setAuthorizationCachingEnabled(true); 126 | return userRealm; 127 | } 128 | 129 | @Bean 130 | public URLPermissionsFilter urlPermissionsFilter() { 131 | return new URLPermissionsFilter(); 132 | } 133 | 134 | @Bean(name = "shrioRedisCacheManager") 135 | @DependsOn(value = "shiroRedisTemplate") 136 | public ShrioRedisCacheManager redisCacheManager() { 137 | ShrioRedisCacheManager cacheManager = new ShrioRedisCacheManager(shiroRedisTemplate()); 138 | cacheManager.createCache("shiro_redis:"); 139 | return cacheManager; 140 | } 141 | 142 | @Bean(name = "shiroRedisTemplate") 143 | public RedisTemplate shiroRedisTemplate() { 144 | RedisTemplate template = new RedisTemplate<>(); 145 | template.setConnectionFactory(connectionFactory()); 146 | return template; 147 | } 148 | 149 | /** 150 | * Redis连接客户端(Session及Shiro缓存管理) 151 | * 152 | * @return 153 | */ 154 | @Primary 155 | @Bean(name = "connectionFactory") 156 | @DependsOn(value = "shiroProperties") 157 | public RedisConnectionFactory connectionFactory() { 158 | JedisConnectionFactory conn = new JedisConnectionFactory(); 159 | conn.setDatabase(shiroProperties().getDatabase()); 160 | conn.setHostName(shiroProperties().getHost()); 161 | conn.setPassword(shiroProperties().getPassword()); 162 | conn.setPort(shiroProperties().getPort()); 163 | conn.setTimeout(shiroProperties().getTimeout()); 164 | log.info("1.初始化Redis缓存服务器(登录用户Session及Shiro缓存管理)... ..."); 165 | return conn; 166 | } 167 | 168 | @Bean 169 | public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 170 | return new LifecycleBeanPostProcessor(); 171 | } 172 | 173 | } -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config; 2 | 3 | import java.io.IOException; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.http.converter.HttpMessageConverter; 11 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 12 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 13 | 14 | import com.fasterxml.jackson.core.JsonGenerator; 15 | import com.fasterxml.jackson.core.JsonProcessingException; 16 | import com.fasterxml.jackson.databind.BeanProperty; 17 | import com.fasterxml.jackson.databind.DeserializationFeature; 18 | import com.fasterxml.jackson.databind.JsonMappingException; 19 | import com.fasterxml.jackson.databind.JsonSerializer; 20 | import com.fasterxml.jackson.databind.MapperFeature; 21 | import com.fasterxml.jackson.databind.ObjectMapper; 22 | import com.fasterxml.jackson.databind.SerializationConfig; 23 | import com.fasterxml.jackson.databind.SerializerProvider; 24 | import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider; 25 | import com.fasterxml.jackson.databind.ser.SerializerFactory; 26 | 27 | /** 28 | * MVC 通用配置 29 | * 30 | * @author Frank Zeng 31 | * 32 | */ 33 | @Configuration 34 | public class MvcConfig extends WebMvcConfigurerAdapter { 35 | 36 | /** 37 | * 自定义JSON输入输出格式 38 | * 39 | * @return 40 | */ 41 | @Bean 42 | public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() { 43 | MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); 44 | ObjectMapper om = new ObjectMapper(); 45 | om.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);// 开启将输出没有JsonView注解的属性,false关闭将输出有JsonView注解的属性 46 | om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 配置该objectMapper在反序列化时,忽略目标对象没有的属性。凡是使用该objectMapper反序列化时,都会拥有该特性。 47 | om.setSerializerProvider(new CustomNullStringSerializerProvider()); 48 | jsonConverter.setObjectMapper(om); 49 | return jsonConverter; 50 | } 51 | 52 | /** 53 | * 扩展输出 54 | */ 55 | @Override 56 | public void extendMessageConverters(List> converters) { 57 | converters.add(customJackson2HttpMessageConverter()); 58 | } 59 | 60 | /** 61 | * 自定义String序列化工具,使null转成""输出。 62 | * 63 | * @author Frank.Zeng 64 | * 65 | */ 66 | public static class CustomNullStringSerializerProvider extends DefaultSerializerProvider { 67 | private static final long serialVersionUID = 1L; 68 | 69 | public CustomNullStringSerializerProvider() { 70 | super(); 71 | } 72 | 73 | public CustomNullStringSerializerProvider(CustomNullStringSerializerProvider provider, 74 | SerializationConfig config, SerializerFactory jsf) { 75 | super(provider, config, jsf); 76 | } 77 | 78 | @Override 79 | public CustomNullStringSerializerProvider createInstance(SerializationConfig config, SerializerFactory jsf) { 80 | return new CustomNullStringSerializerProvider(this, config, jsf); 81 | } 82 | 83 | // 这是最关键的部分,用于处理仅对String类型数据生效的null。 84 | @Override 85 | public JsonSerializer findNullValueSerializer(BeanProperty property) throws JsonMappingException { 86 | if (property.getType().getRawClass().equals(String.class) 87 | || property.getType().getRawClass().equals(Date.class)) { 88 | return EmptyStringSerializer.INSTANCE; 89 | } else if (property.getType().getRawClass().equals(Integer.class)) { 90 | return EmptyIntegerSerializer.INSTANCE; 91 | } else if (property.getType().getRawClass().equals(Double.class)) { 92 | return EmptyDoubleSerializer.INSTANCE; 93 | } else if (property.getType().getRawClass().equals(Boolean.class)) { 94 | return EmptyBooleanSerializer.INSTANCE; 95 | } else if (property.getType().getRawClass().equals(List.class) 96 | || property.getType().getRawClass().equals(Set.class)) { 97 | return EmptyArraySerializer.INSTANCE; 98 | } else { 99 | return super.findNullValueSerializer(property); 100 | } 101 | } 102 | } 103 | 104 | // 自定义序列化 105 | public static class EmptyStringSerializer extends JsonSerializer { 106 | public static final JsonSerializer INSTANCE = new EmptyStringSerializer(); 107 | 108 | private EmptyStringSerializer() { 109 | } 110 | 111 | @Override 112 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 113 | throws IOException, JsonProcessingException { 114 | jsonGenerator.writeString(""); 115 | } 116 | } 117 | 118 | // 自定义序列化 119 | public static class EmptyIntegerSerializer extends JsonSerializer { 120 | public static final JsonSerializer INSTANCE = new EmptyIntegerSerializer(); 121 | 122 | private EmptyIntegerSerializer() { 123 | } 124 | 125 | @Override 126 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 127 | throws IOException, JsonProcessingException { 128 | jsonGenerator.writeNumber(0); 129 | } 130 | } 131 | 132 | // 自定义序列化 133 | public static class EmptyDoubleSerializer extends JsonSerializer { 134 | public static final JsonSerializer INSTANCE = new EmptyDoubleSerializer(); 135 | 136 | private EmptyDoubleSerializer() { 137 | } 138 | 139 | @Override 140 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 141 | throws IOException, JsonProcessingException { 142 | jsonGenerator.writeNumber(0d); 143 | } 144 | } 145 | 146 | // 自定义序列化 147 | public static class EmptyBooleanSerializer extends JsonSerializer { 148 | public static final JsonSerializer INSTANCE = new EmptyBooleanSerializer(); 149 | 150 | private EmptyBooleanSerializer() { 151 | } 152 | 153 | @Override 154 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 155 | throws IOException, JsonProcessingException { 156 | jsonGenerator.writeBoolean(false); 157 | } 158 | } 159 | 160 | // 自定义序列化 161 | public static class EmptyArraySerializer extends JsonSerializer { 162 | public static final JsonSerializer INSTANCE = new EmptyArraySerializer(); 163 | 164 | private EmptyArraySerializer() { 165 | } 166 | 167 | @Override 168 | public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) 169 | throws IOException, JsonProcessingException { 170 | int[] a = {}; 171 | jsonGenerator.writeArray(a, 0, 0); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/org/jdonee/cooking/config/redis/SecondaryRedisConfig.java: -------------------------------------------------------------------------------- 1 | package org.jdonee.cooking.config.redis; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.cache.CacheManager; 7 | import org.springframework.cache.annotation.CachingConfigurerSupport; 8 | import org.springframework.cache.annotation.EnableCaching; 9 | import org.springframework.cache.interceptor.KeyGenerator; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.data.redis.cache.RedisCacheManager; 13 | import org.springframework.data.redis.connection.RedisConnectionFactory; 14 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 15 | import org.springframework.data.redis.core.RedisTemplate; 16 | import org.springframework.data.redis.core.StringRedisTemplate; 17 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; 18 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 19 | import org.springframework.data.redis.serializer.RedisSerializer; 20 | import org.springframework.data.redis.serializer.StringRedisSerializer; 21 | import org.springframework.session.data.redis.RedisOperationsSessionRepository; 22 | import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; 23 | 24 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 25 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 26 | import com.fasterxml.jackson.annotation.PropertyAccessor; 27 | import com.fasterxml.jackson.databind.DeserializationFeature; 28 | import com.fasterxml.jackson.databind.ObjectMapper; 29 | 30 | import lombok.extern.slf4j.Slf4j; 31 | import redis.clients.jedis.JedisPoolConfig; 32 | 33 | /** 34 | * Redis服务器对象缓存配置(对象缓存和Session缓存) 35 | * 36 | * @author Frank.Zeng 37 | * 38 | */ 39 | @Configuration 40 | @EnableCaching 41 | @EnableRedisHttpSession 42 | @Slf4j 43 | public class SecondaryRedisConfig extends CachingConfigurerSupport { 44 | 45 | /** 46 | * 加载属性文件数据 47 | * 48 | * @return 49 | */ 50 | @Bean 51 | public MyRedisProperties redisProperties() { 52 | return new MyRedisProperties(); 53 | } 54 | 55 | /** 56 | * 主键生成器 57 | * 58 | * @return 59 | */ 60 | @Bean 61 | public KeyGenerator commonKeyGenerator() { 62 | return new KeyGenerator() { 63 | @Override 64 | public Object generate(Object target, Method method, Object... params) { 65 | StringBuilder sb = new StringBuilder(); 66 | sb.append(target.getClass().getName()); 67 | sb.append(method.getName()); 68 | for (Object obj : params) { 69 | sb.append(obj.toString()); 70 | } 71 | String key = sb.toString(); 72 | log.info("key:" + key); 73 | return key; 74 | } 75 | }; 76 | 77 | } 78 | 79 | @Bean 80 | public CacheManager cacheManager(@Qualifier("secondaryStringRedisTemplate") RedisTemplate redisTemplate) { 81 | CacheManager redisCacheManager = new RedisCacheManager(redisTemplate); 82 | return redisCacheManager; 83 | } 84 | 85 | private JedisPoolConfig jedisPoolConfig() { 86 | JedisPoolConfig config = new JedisPoolConfig(); 87 | MyRedisProperties.Pool props = redisProperties().getPool(); 88 | config.setMaxTotal(props.getMaxActive()); 89 | config.setMaxIdle(props.getMaxIdle()); 90 | config.setMinIdle(props.getMinIdle()); 91 | config.setMaxWaitMillis(props.getMaxWait()); 92 | return config; 93 | } 94 | 95 | @Bean(name = "secondaryRedisConnectionFactory") 96 | public RedisConnectionFactory secondaryRedisConnectionFactory() { 97 | JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig()); 98 | redisConnectionFactory.setDatabase(redisProperties().getSecondaryDatabase()); 99 | redisConnectionFactory.setPassword(redisProperties().getPassword()); 100 | redisConnectionFactory.setHostName(redisProperties().getHost()); 101 | redisConnectionFactory.setTimeout(redisProperties().getTimeout()); 102 | redisConnectionFactory.setPort(redisProperties().getPort()); 103 | redisConnectionFactory.afterPropertiesSet(); 104 | log.info("2.1 初始化Redis缓存服务器(普通对象)... ..."); 105 | return redisConnectionFactory; 106 | } 107 | 108 | @Bean(name = "secondaryStringRedisTemplate") 109 | public RedisTemplate redisTemplate( 110 | @Qualifier("secondaryRedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) { 111 | log.info("2.2 初始化Redis模板(普通对象)... ..."); 112 | StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory); 113 | ObjectMapper om = new ObjectMapper(); 114 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 115 | om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 116 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 117 | om.setSerializationInclusion(Include.NON_EMPTY);// 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper 118 | GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om); 119 | template.setValueSerializer(jackson2JsonRedisSerializer); 120 | // template.afterPropertiesSet(); 121 | return template; 122 | } 123 | 124 | /** 125 | * 与Session有关设置链接 126 | * 127 | * @return 128 | */ 129 | @Bean 130 | public RedisOperationsSessionRepository sessionRepository() { 131 | RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository( 132 | secondaryRedisConnectionFactory()); 133 | sessionRepository.setDefaultMaxInactiveInterval(redisProperties().getSessionExpire());// 设置session的有效时长 134 | return sessionRepository; 135 | } 136 | 137 | /** 138 | * RedisTemplate 139 | * 140 | * @return 141 | */ 142 | @Bean(name = "redisTemplate") 143 | public RedisTemplate sessionRedisTemplate() { 144 | RedisTemplate template = new RedisTemplate<>(); 145 | template.setConnectionFactory(secondaryRedisConnectionFactory()); 146 | RedisSerializer stringSerializer = new StringRedisSerializer(); 147 | template.setKeySerializer(stringSerializer); 148 | template.setValueSerializer(sessionRedisSerializer()); 149 | template.setHashKeySerializer(stringSerializer); 150 | template.setHashValueSerializer(sessionRedisSerializer()); 151 | template.afterPropertiesSet(); 152 | return template; 153 | } 154 | 155 | /** 156 | * 设置redisTemplate的存储格式(在此与Session没有什么关系) 157 | * 158 | * @return 159 | */ 160 | @Bean 161 | @SuppressWarnings("rawtypes") 162 | public RedisSerializer sessionRedisSerializer() { 163 | return new Jackson2JsonRedisSerializer(Object.class); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dashboard 8 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 45 | 46 |
47 |
48 | 64 |
65 |

Dashboard

66 |
67 |
68 | Generic placeholder thumbnail 69 |

Label

70 | Something else 71 |
72 |
73 | Generic placeholder thumbnail 74 |

Label

75 | Something else 76 |
77 |
78 | Generic placeholder thumbnail 79 |

Label

80 | Something else 81 |
82 |
83 | Generic placeholder thumbnail 84 |

Label

85 | Something else 86 |
87 |
88 | 89 |

Section title

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 | 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 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 |
#HeaderHeaderHeaderHeader
1,001Loremipsumdolorsit
1,002ametconsecteturadipiscingelit
1,003IntegernecodioPraesent
1,003liberoSedcursusante
1,004dapibusdiamSednisi
1,005Nullaquissemat
1,006nibhelementumimperdietDuis
1,007sagittisipsumPraesentmauris
1,008Fuscenectellussed
1,009auguesemperportaMauris
1,010massaVestibulumlaciniaarcu
1,011egetnullaClassaptent
1,012tacitisociosquadlitora
1,013torquentperconubianostra
1,014perinceptoshimenaeosCurabitur
1,015sodalesligulainlibero
216 |
217 |
218 |
219 |
220 | 221 | 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /src/main/resources/static/layer/skin/layer.css: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | @Name: layer's style 4 | @Author: 贤心 5 | @Blog: sentsin.com 6 | 7 | */.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}*html{background-image:url(about:blank);background-attachment:fixed}html #layui_layer_skinlayercss{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{top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;box-shadow:1px 1px 50px rgba(0,0,0,.3);border-radius:2px;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.3);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-moves{position:absolute;border:3px solid #666;border:3px solid rgba(0,0,0,.5);cursor:move;background-color:#fff;background-color:rgba(255,255,255,.3);filter:alpha(opacity=50)}.layui-layer-load{background:url(default/loading-0.gif) center center no-repeat #fff}.layui-layer-ico{background:url(default/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}@-webkit-keyframes bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes 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{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.03);transform:scale(1.03)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.03);-ms-transform:scale(1.03);transform:scale(1.03)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes 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 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:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes 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:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes 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 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:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes 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 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:rollIn;animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes 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 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:shake;animation-name: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:#333;overflow:hidden;background-color:#F8F8F8;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:0 -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 10px 12px;pointer-events:auto}.layui-layer-btn a{height:28px;line-height:28px;margin:0 6px;padding:0 15px;border:1px solid #dedede;background-color:#f1f1f1;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:.7}.layui-layer-btn .layui-layer-btn0{border-color:#4898d5;background-color:#2e8ded;color:#fff}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;font-size:14px;overflow:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.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:1px solid #D3D4D3;box-shadow:none}.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:20px 20px 20px 55px;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 .layui-layer-content{overflow:hidden}.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(default/loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(default/loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(default/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:5px 10px;font-size:12px;_float:left;border-radius:3px;box-shadow:1px 1px 3px rgba(0,0,0,.3);background-color:#F90;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:#F90}.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:1px;border-bottom-style:solid;border-bottom-color:#F90}.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:10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#BBB5B5;border:none}.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}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(default/icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;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;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;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.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s}.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} -------------------------------------------------------------------------------- /src/main/resources/static/layer/layer.js: -------------------------------------------------------------------------------- 1 | /*! layer-v2.3 弹层组件 License LGPL http://layer.layui.com/ By 贤心 */ 2 | ;!function(a,b){"use strict";var c,d,e={getPath:function(){var a=document.scripts,b=a[a.length-1],c=b.src;if(!b.getAttribute("merge"))return c.substring(0,c.lastIndexOf("/")+1)}(),enter:function(a){13===a.keyCode&&a.preventDefault()},config:{},end:{},btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"]},f={v:"2.3",ie6:!!a.ActiveXObject&&!a.XMLHttpRequest,index:0,path:e.getPath,config:function(a,b){var d=0;return a=a||{},f.cache=e.config=c.extend(e.config,a),f.path=e.config.path||f.path,"string"==typeof a.extend&&(a.extend=[a.extend]),f.use("skin/layer.css",a.extend&&a.extend.length>0?function g(){var c=a.extend;f.use(c[c[d]?d:d-1],d'+(i?f.title[0]:f.title)+"":"";return f.zIndex=g,b([f.shade?'
':"",'
'+(a&&2!=f.type?"":k)+'
'+(0==f.type&&-1!==f.icon?'':"")+(1==f.type&&a?"":f.content||"")+'
'+function(){var a=j?'':"";return f.closeBtn&&(a+=''),a}()+""+(f.btn?function(){var a="";"string"==typeof f.btn&&(f.btn=[f.btn]);for(var b=0,c=f.btn.length;c>b;b++)a+=''+f.btn[b]+"";return'
'+a+"
"}():"")+"
"],k),c},g.pt.creat=function(){var a=this,b=a.config,g=a.index,i=b.content,j="object"==typeof i;if(!c("#"+b.id)[0]){switch("string"==typeof b.area&&(b.area="auto"===b.area?["",""]:[b.area,""]),b.type){case 0:b.btn="btn"in b?b.btn:e.btn[0],f.closeAll("dialog");break;case 2:var i=b.content=j?b.content:[b.content||"http://layer.layui.com","auto"];b.content='';break;case 3:b.title=!1,b.closeBtn=!1,-1===b.icon&&0===b.icon,f.closeAll("loading");break;case 4:j||(b.content=[b.content,"body"]),b.follow=b.content[1],b.content=b.content[0]+'',b.title=!1,b.fix=!1,b.tips="object"==typeof b.tips?b.tips:[b.tips,!0],b.tipsMore||f.closeAll("tips")}a.vessel(j,function(d,e){c("body").append(d[0]),j?function(){2==b.type||4==b.type?function(){c("body").append(d[1])}():function(){i.parents("."+h[0])[0]||(i.show().addClass("layui-layer-wrap").wrap(d[1]),c("#"+h[0]+g).find("."+h[5]).before(e))}()}():c("body").append(d[1]),a.layero=c("#"+h[0]+g),b.scrollbar||h.html.css("overflow","hidden").attr("layer-full",g)}).auto(g),2==b.type&&f.ie6&&a.layero.find("iframe").attr("src",i[0]),c(document).off("keydown",e.enter).on("keydown",e.enter),a.layero.on("keydown",function(a){c(document).off("keydown",e.enter)}),4==b.type?a.tips():a.offset(),b.fix&&d.on("resize",function(){a.offset(),(/^\d+%$/.test(b.area[0])||/^\d+%$/.test(b.area[1]))&&a.auto(g),4==b.type&&a.tips()}),b.time<=0||setTimeout(function(){f.close(a.index)},b.time),a.move().callback()}},g.pt.auto=function(a){function b(a){a=g.find(a),a.height(i[1]-j-k-2*(0|parseFloat(a.css("padding"))))}var e=this,f=e.config,g=c("#"+h[0]+a);""===f.area[0]&&f.maxWidth>0&&(/MSIE 7/.test(navigator.userAgent)&&f.btn&&g.width(g.innerWidth()),g.outerWidth()>f.maxWidth&&g.width(f.maxWidth));var i=[g.innerWidth(),g.innerHeight()],j=g.find(h[1]).outerHeight()||0,k=g.find("."+h[6]).outerHeight()||0;switch(f.type){case 2:b("iframe");break;default:""===f.area[1]?f.fix&&i[1]>=d.height()&&(i[1]=d.height(),b("."+h[5])):b("."+h[5])}return e},g.pt.offset=function(){var a=this,b=a.config,c=a.layero,e=[c.outerWidth(),c.outerHeight()],f="object"==typeof b.offset;a.offsetTop=(d.height()-e[1])/2,a.offsetLeft=(d.width()-e[0])/2,f?(a.offsetTop=b.offset[0],a.offsetLeft=b.offset[1]||a.offsetLeft):"auto"!==b.offset&&(a.offsetTop=b.offset,"rb"===b.offset&&(a.offsetTop=d.height()-e[1],a.offsetLeft=d.width()-e[0])),b.fix||(a.offsetTop=/%$/.test(a.offsetTop)?d.height()*parseFloat(a.offsetTop)/100:parseFloat(a.offsetTop),a.offsetLeft=/%$/.test(a.offsetLeft)?d.width()*parseFloat(a.offsetLeft)/100:parseFloat(a.offsetLeft),a.offsetTop+=d.scrollTop(),a.offsetLeft+=d.scrollLeft()),c.css({top:a.offsetTop,left:a.offsetLeft})},g.pt.tips=function(){var a=this,b=a.config,e=a.layero,f=[e.outerWidth(),e.outerHeight()],g=c(b.follow);g[0]||(g=c("body"));var i={width:g.outerWidth(),height:g.outerHeight(),top:g.offset().top,left:g.offset().left},j=e.find(".layui-layer-TipsG"),k=b.tips[0];b.tips[1]||j.remove(),i.autoLeft=function(){i.left+f[0]-d.width()>0?(i.tipLeft=i.left+i.width-f[0],j.css({right:12,left:"auto"})):i.tipLeft=i.left},i.where=[function(){i.autoLeft(),i.tipTop=i.top-f[1]-10,j.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",b.tips[1])},function(){i.tipLeft=i.left+i.width+10,i.tipTop=i.top,j.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",b.tips[1])},function(){i.autoLeft(),i.tipTop=i.top+i.height+10,j.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",b.tips[1])},function(){i.tipLeft=i.left-f[0]-10,i.tipTop=i.top,j.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",b.tips[1])}],i.where[k-1](),1===k?i.top-(d.scrollTop()+f[1]+16)<0&&i.where[2]():2===k?d.width()-(i.left+i.width+f[0]+16)>0||i.where[3]():3===k?i.top-d.scrollTop()+i.height+f[1]+16-d.height()>0&&i.where[0]():4===k&&f[0]+16-i.left>0&&i.where[1](),e.find("."+h[5]).css({"background-color":b.tips[1],"padding-right":b.closeBtn?"30px":""}),e.css({left:i.tipLeft,top:i.tipTop})},g.pt.move=function(){var a=this,b=a.config,e={setY:0,moveLayer:function(){var a=e.layero,b=parseInt(a.css("margin-left")),c=parseInt(e.move.css("left"));0===b||(c-=b),"fixed"!==a.css("position")&&(c-=a.parent().offset().left,e.setY=0),a.css({left:c,top:parseInt(e.move.css("top"))-e.setY})}},f=a.layero.find(b.move);return b.move&&f.attr("move","ok"),f.css({cursor:b.move?"move":"auto"}),c(b.move).on("mousedown",function(a){if(a.preventDefault(),"ok"===c(this).attr("move")){e.ismove=!0,e.layero=c(this).parents("."+h[0]);var f=e.layero.offset().left,g=e.layero.offset().top,i=e.layero.outerWidth()-6,j=e.layero.outerHeight()-6;c("#layui-layer-moves")[0]||c("body").append('
'),e.move=c("#layui-layer-moves"),b.moveType&&e.move.css({visibility:"hidden"}),e.moveX=a.pageX-e.move.position().left,e.moveY=a.pageY-e.move.position().top,"fixed"!==e.layero.css("position")||(e.setY=d.scrollTop())}}),c(document).mousemove(function(a){if(e.ismove){var c=a.pageX-e.moveX,f=a.pageY-e.moveY;if(a.preventDefault(),!b.moveOut){e.setY=d.scrollTop();var g=d.width()-e.move.outerWidth(),h=e.setY;0>c&&(c=0),c>g&&(c=g),h>f&&(f=h),f>d.height()-e.move.outerHeight()+e.setY&&(f=d.height()-e.move.outerHeight()+e.setY)}e.move.css({left:c,top:f}),b.moveType&&e.moveLayer(),c=f=g=h=null}}).mouseup(function(){try{e.ismove&&(e.moveLayer(),e.move.remove(),b.moveEnd&&b.moveEnd()),e.ismove=!1}catch(a){e.ismove=!1}}),a},g.pt.callback=function(){function a(){var a=g.cancel&&g.cancel(b.index,d);a===!1||f.close(b.index)}var b=this,d=b.layero,g=b.config;b.openLayer(),g.success&&(2==g.type?d.find("iframe").on("load",function(){g.success(d,b.index)}):g.success(d,b.index)),f.ie6&&b.IE6(d),d.find("."+h[6]).children("a").on("click",function(){var a=c(this).index();if(0===a)g.yes?g.yes(b.index,d):g.btn1?g.btn1(b.index,d):f.close(b.index);else{var e=g["btn"+(a+1)]&&g["btn"+(a+1)](b.index,d);e===!1||f.close(b.index)}}),d.find("."+h[7]).on("click",a),g.shadeClose&&c("#layui-layer-shade"+b.index).on("click",function(){f.close(b.index)}),d.find(".layui-layer-min").on("click",function(){f.min(b.index,g),g.min&&g.min(d)}),d.find(".layui-layer-max").on("click",function(){c(this).hasClass("layui-layer-maxmin")?(f.restore(b.index),g.restore&&g.restore(d)):(f.full(b.index,g),g.full&&g.full(d))}),g.end&&(e.end[b.index]=g.end)},e.reselect=function(){c.each(c("select"),function(a,b){var d=c(this);d.parents("."+h[0])[0]||1==d.attr("layer")&&c("."+h[0]).length<1&&d.removeAttr("layer").show(),d=null})},g.pt.IE6=function(a){function b(){a.css({top:f+(e.config.fix?d.scrollTop():0)})}var e=this,f=a.offset().top;b(),d.scroll(b),c("select").each(function(a,b){var d=c(this);d.parents("."+h[0])[0]||"none"===d.css("display")||d.attr({layer:"1"}).hide(),d=null})},g.pt.openLayer=function(){var a=this;f.zIndex=a.config.zIndex,f.setTop=function(a){var b=function(){f.zIndex++,a.css("z-index",f.zIndex+1)};return f.zIndex=parseInt(a[0].style.zIndex),a.on("mousedown",b),f.zIndex}},e.record=function(a){var b=[a.outerWidth(),a.outerHeight(),a.position().top,a.position().left+parseFloat(a.css("margin-left"))];a.find(".layui-layer-max").addClass("layui-layer-maxmin"),a.attr({area:b})},e.rescollbar=function(a){h.html.attr("layer-full")==a&&(h.html[0].style.removeProperty?h.html[0].style.removeProperty("overflow"):h.html[0].style.removeAttribute("overflow"),h.html.removeAttr("layer-full"))},a.layer=f,f.getChildFrame=function(a,b){return b=b||c("."+h[4]).attr("times"),c("#"+h[0]+b).find("iframe").contents().find(a)},f.getFrameIndex=function(a){return c("#"+a).parents("."+h[4]).attr("times")},f.iframeAuto=function(a){if(a){var b=f.getChildFrame("html",a).outerHeight(),d=c("#"+h[0]+a),e=d.find(h[1]).outerHeight()||0,g=d.find("."+h[6]).outerHeight()||0;d.css({height:b+e+g}),d.find("iframe").css({height:b})}},f.iframeSrc=function(a,b){c("#"+h[0]+a).find("iframe").attr("src",b)},f.style=function(a,b){var d=c("#"+h[0]+a),f=d.attr("type"),g=d.find(h[1]).outerHeight()||0,i=d.find("."+h[6]).outerHeight()||0;(f===e.type[1]||f===e.type[2])&&(d.css(b),f===e.type[2]&&d.find("iframe").css({height:parseFloat(b.height)-g-i}))},f.min=function(a,b){var d=c("#"+h[0]+a),g=d.find(h[1]).outerHeight()||0;e.record(d),f.style(a,{width:180,height:g,overflow:"hidden"}),d.find(".layui-layer-min").hide(),"page"===d.attr("type")&&d.find(h[4]).hide(),e.rescollbar(a)},f.restore=function(a){var b=c("#"+h[0]+a),d=b.attr("area").split(",");b.attr("type");f.style(a,{width:parseFloat(d[0]),height:parseFloat(d[1]),top:parseFloat(d[2]),left:parseFloat(d[3]),overflow:"visible"}),b.find(".layui-layer-max").removeClass("layui-layer-maxmin"),b.find(".layui-layer-min").show(),"page"===b.attr("type")&&b.find(h[4]).show(),e.rescollbar(a)},f.full=function(a){var b,g=c("#"+h[0]+a);e.record(g),h.html.attr("layer-full")||h.html.css("overflow","hidden").attr("layer-full",a),clearTimeout(b),b=setTimeout(function(){var b="fixed"===g.css("position");f.style(a,{top:b?0:d.scrollTop(),left:b?0:d.scrollLeft(),width:d.width(),height:d.height()}),g.find(".layui-layer-min").hide()},100)},f.title=function(a,b){var d=c("#"+h[0]+(b||f.index)).find(h[1]);d.html(a)},f.close=function(a){var b=c("#"+h[0]+a),d=b.attr("type");if(b[0]){if(d===e.type[1]&&"object"===b.attr("conType")){b.children(":not(."+h[5]+")").remove();for(var g=0;2>g;g++)b.find(".layui-layer-wrap").unwrap().hide()}else{if(d===e.type[2])try{var i=c("#"+h[4]+a)[0];i.contentWindow.document.write(""),i.contentWindow.close(),b.find("."+h[5])[0].removeChild(i)}catch(j){}b[0].innerHTML="",b.remove()}c("#layui-layer-moves, #layui-layer-shade"+a).remove(),f.ie6&&e.reselect(),e.rescollbar(a),c(document).off("keydown",e.enter),"function"==typeof e.end[a]&&e.end[a](),delete e.end[a]}},f.closeAll=function(a){c.each(c("."+h[0]),function(){var b=c(this),d=a?b.attr("type")===a:1;d&&f.close(b.attr("times")),d=null})};var i=f.cache||{},j=function(a){return i.skin?" "+i.skin+" "+i.skin+"-"+a:""};f.prompt=function(a,b){a=a||{},"function"==typeof a&&(b=a);var d,e=2==a.formType?'":function(){return''}();return f.open(c.extend({btn:["确定","取消"],content:e,skin:"layui-layer-prompt"+j("prompt"),success:function(a){d=a.find(".layui-layer-input"),d.focus()},yes:function(c){var e=d.val();""===e?d.focus():e.length>(a.maxlength||500)?f.tips("最多输入"+(a.maxlength||500)+"个字数",d,{tips:1}):b&&b(e,c,d)}},a))},f.tab=function(a){a=a||{};var b=a.tab||{};return f.open(c.extend({type:1,skin:"layui-layer-tab"+j("tab"),title:function(){var a=b.length,c=1,d="";if(a>0)for(d=''+b[0].title+"";a>c;c++)d+=""+b[c].title+"";return d}(),content:'
    '+function(){var a=b.length,c=1,d="";if(a>0)for(d='
  • '+(b[0].content||"no content")+"
  • ";a>c;c++)d+='
  • '+(b[c].content||"no content")+"
  • ";return d}()+"
",success:function(b){var d=b.find(".layui-layer-title").children(),e=b.find(".layui-layer-tabmain").children();d.on("mousedown",function(b){b.stopPropagation?b.stopPropagation():b.cancelBubble=!0;var d=c(this),f=d.index();d.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow"),e.eq(f).show().siblings().hide(),"function"==typeof a.change&&a.change(f)})}},a))},f.photos=function(b,d,e){function g(a,b,c){var d=new Image;return d.src=a,d.complete?b(d):(d.onload=function(){d.onload=null,b(d)},void(d.onerror=function(a){d.onerror=null,c(a)}))}var h={};if(b=b||{},b.photos){var i=b.photos.constructor===Object,k=i?b.photos:{},l=k.data||[],m=k.start||0;if(h.imgIndex=(0|m)+1,b.img=b.img||"img",i){if(0===l.length)return f.msg("没有图片")}else{var n=c(b.photos),o=function(){l=[],n.find(b.img).each(function(a){var b=c(this);b.attr("layer-index",a),l.push({alt:b.attr("alt"),pid:b.attr("layer-pid"),src:b.attr("layer-src")||b.attr("src"),thumb:b.attr("src")})})};if(o(),0===l.length)return;if(d||n.on("click",b.img,function(){var a=c(this),d=a.attr("layer-index");f.photos(c.extend(b,{photos:{start:d,data:l,tab:b.tab},full:b.full}),!0),o()}),!d)return}h.imgprev=function(a){h.imgIndex--,h.imgIndex<1&&(h.imgIndex=l.length),h.tabimg(a)},h.imgnext=function(a,b){h.imgIndex++,h.imgIndex>l.length&&(h.imgIndex=1,b)||h.tabimg(a)},h.keyup=function(a){if(!h.end){var b=a.keyCode;a.preventDefault(),37===b?h.imgprev(!0):39===b?h.imgnext(!0):27===b&&f.close(h.index)}},h.tabimg=function(a){l.length<=1||(k.start=h.imgIndex-1,f.close(h.index),f.photos(b,!0,a))},h.event=function(){h.bigimg.hover(function(){h.imgsee.show()},function(){h.imgsee.hide()}),h.bigimg.find(".layui-layer-imgprev").on("click",function(a){a.preventDefault(),h.imgprev()}),h.bigimg.find(".layui-layer-imgnext").on("click",function(a){a.preventDefault(),h.imgnext()}),c(document).on("keyup",h.keyup)},h.loadi=f.load(1,{shade:"shade"in b?!1:.9,scrollbar:!1}),g(l[m].src,function(d){f.close(h.loadi),h.index=f.open(c.extend({type:1,area:function(){var e=[d.width,d.height],f=[c(a).width()-50,c(a).height()-50];return!b.full&&e[0]>f[0]&&(e[0]=f[0],e[1]=e[0]*d.height/d.width),[e[0]+"px",e[1]+"px"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:".layui-layer-phimg img",moveType:1,scrollbar:!1,moveOut:!0,shift:5*Math.random()|0,skin:"layui-layer-photos"+j("photos"),content:'
'+(l[m].alt||
'+(l.length>1?'':"")+'
'+(l[m].alt||"")+""+h.imgIndex+"/"+l.length+"
",success:function(a,c){h.bigimg=a.find(".layui-layer-phimg"),h.imgsee=a.find(".layui-layer-imguide,.layui-layer-imgbar"),h.event(a),b.tab&&b.tab(l[m],a)},end:function(){h.end=!0,c(document).off("keyup",h.keyup)}},b))},function(){f.close(h.loadi),f.msg("当前图片地址异常
是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){l.length>1&&h.imgnext(!0,!0)}})})}},e.run=function(){c=jQuery,d=c(a),h.html=c("html"),f.open=function(a){var b=new g(a);return b.index}},"function"==typeof define?define(function(){return e.run(),f}):function(){e.run(),f.use("skin/layer.css")}()}(window); -------------------------------------------------------------------------------- /src/main/resources/static/base/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 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)} -------------------------------------------------------------------------------- /src/main/resources/static/base/js/holder.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | Holder - client side image placeholders 4 | Version 2.9.0+f2dkw 5 | © 2015 Ivan Malopinsky - http://imsky.co 6 | 7 | Site: http://holderjs.com 8 | Issues: https://github.com/imsky/holder/issues 9 | License: MIT 10 | 11 | */ 12 | !function(e){if(e.document){var t=e.document;t.querySelectorAll||(t.querySelectorAll=function(n){var r,i=t.createElement("style"),o=[];for(t.documentElement.firstChild.appendChild(i),t._qsa=[],i.styleSheet.cssText=n+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",e.scrollBy(0,0),i.parentNode.removeChild(i);t._qsa.length;)r=t._qsa.shift(),r.style.removeAttribute("x-qsa"),o.push(r);return t._qsa=null,o}),t.querySelector||(t.querySelector=function(e){var n=t.querySelectorAll(e);return n.length?n[0]:null}),t.getElementsByClassName||(t.getElementsByClassName=function(e){return e=String(e).replace(/^|\s+/g,"."),t.querySelectorAll(e)}),Object.keys||(Object.keys=function(e){if(e!==Object(e))throw TypeError("Object.keys called on non-object");var t,n=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&n.push(t);return n}),Array.prototype.forEach||(Array.prototype.forEach=function(e){if(void 0===this||null===this)throw TypeError();var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw TypeError();var r,i=arguments[1];for(r=0;n>r;r++)r in t&&e.call(i,t[r],r,t)}),function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";e.atob=e.atob||function(e){e=String(e);var n,r=0,i=[],o=0,a=0;if(e=e.replace(/\s/g,""),e.length%4===0&&(e=e.replace(/=+$/,"")),e.length%4===1)throw Error("InvalidCharacterError");if(/[^+/0-9A-Za-z]/.test(e))throw Error("InvalidCharacterError");for(;r>16&255)),i.push(String.fromCharCode(o>>8&255)),i.push(String.fromCharCode(255&o)),a=0,o=0),r+=1;return 12===a?(o>>=4,i.push(String.fromCharCode(255&o))):18===a&&(o>>=2,i.push(String.fromCharCode(o>>8&255)),i.push(String.fromCharCode(255&o))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var n,r,i,o,a,s,l,h=0,u=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;h>2,a=(3&n)<<4|r>>4,s=(15&r)<<2|i>>6,l=63&i,h===e.length+2?(s=64,l=64):h===e.length+1&&(l=64),u.push(t.charAt(o),t.charAt(a),t.charAt(s),t.charAt(l));return u.join("")}}(e),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(){if("performance"in e==!1&&(e.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in e.performance==!1){var t=Date.now();performance.timing&&performance.timing.navigationStart&&(t=performance.timing.navigationStart),e.performance.now=function(){return Date.now()-t}}}(),e.requestAnimationFrame||(e.webkitRequestAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return webkitRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=webkitCancelAnimationFrame}(e):e.mozRequestAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return mozRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=mozCancelAnimationFrame}(e):!function(e){e.requestAnimationFrame=function(t){return e.setTimeout(t,1e3/60)},e.cancelAnimationFrame=e.clearTimeout}(e))}}(this),function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Holder=t():e.Holder=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){(function(t){function r(e,t,n,r){var a=i(n.substr(n.lastIndexOf(e.domain)),e);a&&o({mode:null,el:r,flags:a,engineSettings:t})}function i(e,t){var n={theme:T(F.settings.themes.gray,null),stylesheets:t.stylesheets,instanceOptions:t},r=e.split("?"),i=r[0].split("/");n.holderURL=e;var o=i[1],a=o.match(/([\d]+p?)x([\d]+p?)/);if(!a)return!1;if(n.fluid=-1!==o.indexOf("p"),n.dimensions={width:a[1].replace("p","%"),height:a[2].replace("p","%")},2===r.length){var s=v.parse(r[1]);if(s.bg&&(n.theme.bg=w.parseColor(s.bg)),s.fg&&(n.theme.fg=w.parseColor(s.fg)),s.bg&&!s.fg&&(n.autoFg=!0),s.theme&&n.instanceOptions.themes.hasOwnProperty(s.theme)&&(n.theme=T(n.instanceOptions.themes[s.theme],null)),s.text&&(n.text=s.text),s.textmode&&(n.textmode=s.textmode),s.size&&(n.size=s.size),s.font&&(n.font=s.font),s.align&&(n.align=s.align),s.lineWrap&&(n.lineWrap=s.lineWrap),n.nowrap=w.truthy(s.nowrap),n.auto=w.truthy(s.auto),n.outline=w.truthy(s.outline),w.truthy(s.random)){F.vars.cache.themeKeys=F.vars.cache.themeKeys||Object.keys(n.instanceOptions.themes);var l=F.vars.cache.themeKeys[0|Math.random()*F.vars.cache.themeKeys.length];n.theme=T(n.instanceOptions.themes[l],null)}}return n}function o(e){var t=e.mode,n=e.el,r=e.flags,i=e.engineSettings,o=r.dimensions,s=r.theme,l=o.width+"x"+o.height;t=null==t?r.fluid?"fluid":"image":t;var d=/holder_([a-z]+)/g,c=!1;if(null!=r.text&&(s.text=r.text,"object"===n.nodeName.toLowerCase())){for(var f=s.text.split("\\n"),p=0;p1){var b,x=0,A=0,C=0;w=new s.Group("line"+C),("left"===e.align||"right"===e.align)&&(o=e.width*(1-2*(1-r)));for(var E=0;E=o||k===!0)&&(t(g,w,x,g.properties.leading),g.add(w),x=0,A+=g.properties.leading,C+=1,w=new s.Group("line"+C),w.y=A),k!==!0&&(v.moveTo(x,0),x+=m.spaceWidth+T.width,w.add(v))}if(t(g,w,x,g.properties.leading),g.add(w),"left"===e.align)g.moveTo(e.width-i,null,null);else if("right"===e.align){for(b in g.children)w=g.children[b],w.moveTo(e.width-w.width,null,null);g.moveTo(0-(e.width-i),null,null)}else{for(b in g.children)w=g.children[b],w.moveTo((g.width-w.width)/2,null,null);g.moveTo((e.width-g.width)/2,null,null)}g.moveTo(null,(e.height-g.height)/2,null),(e.height-g.height)/2<0&&g.moveTo(null,0,null)}else v=new s.Text(e.text),w=new s.Group("line0"),w.add(v),g.add(w),"left"===e.align?g.moveTo(e.width-i,null,null):"right"===e.align?g.moveTo(0-(e.width-i),null,null):g.moveTo((e.width-m.boundingBox.width)/2,null,null),g.moveTo(null,(e.height-m.boundingBox.height)/2,null);return a}function l(e,t,n,r){var i=parseInt(e,10),o=parseInt(t,10),a=Math.max(i,o),s=Math.min(i,o),l=.8*Math.min(s,a*r);return Math.round(Math.max(n,l))}function h(e){var t;t=null==e||null==e.nodeType?F.vars.resizableImages:[e];for(var n=0,r=t.length;r>n;n++){var i=t[n];if(i.holderData){var o=i.holderData.flags,s=k(i);if(s){if(!i.holderData.resizeUpdate)continue;if(o.fluid&&o.auto){var l=i.holderData.fluidConfig;switch(l.mode){case"width":s.height=s.width/l.ratio;break;case"height":s.width=s.height*l.ratio}}var h={mode:"image",holderSettings:{dimensions:s,theme:o.theme,flags:o},el:i,engineSettings:i.holderData.engineSettings};"exact"==o.textmode&&(o.exactDimensions=s,h.holderSettings.dimensions=o.dimensions),a(h)}else f(i)}}}function u(e){if(e.holderData){var t=k(e);if(t){var n=e.holderData.flags,r={fluidHeight:"%"==n.dimensions.height.slice(-1),fluidWidth:"%"==n.dimensions.width.slice(-1),mode:null,initialDimensions:t};r.fluidWidth&&!r.fluidHeight?(r.mode="width",r.ratio=r.initialDimensions.width/parseFloat(n.dimensions.height)):!r.fluidWidth&&r.fluidHeight&&(r.mode="height",r.ratio=parseFloat(n.dimensions.width)/r.initialDimensions.height),e.holderData.fluidConfig=r}else f(e)}}function d(){var e,n=[],r=Object.keys(F.vars.invisibleImages);r.forEach(function(t){e=F.vars.invisibleImages[t],k(e)&&"img"==e.nodeName.toLowerCase()&&(n.push(e),delete F.vars.invisibleImages[t])}),n.length&&O.run({images:n}),setTimeout(function(){t.requestAnimationFrame(d)},10)}function c(){F.vars.visibilityCheckStarted||(t.requestAnimationFrame(d),F.vars.visibilityCheckStarted=!0)}function f(e){e.holderData.invisibleId||(F.vars.invisibleId+=1,F.vars.invisibleImages["i"+F.vars.invisibleId]=e,e.holderData.invisibleId=F.vars.invisibleId)}function p(e){F.vars.debounceTimer||e.call(this),F.vars.debounceTimer&&t.clearTimeout(F.vars.debounceTimer),F.vars.debounceTimer=t.setTimeout(function(){F.vars.debounceTimer=null,e.call(this)},F.setup.debounce)}function g(){p(function(){h(null)})}var m=n(2),v=n(3),y=n(6),w=n(7),b=n(8),x=n(9),S=n(10),A=n(11),C=n(12),E=n(15),T=w.extend,k=w.dimensionCheck,j=A.svg_ns,O={version:A.version,addTheme:function(e,t){return null!=e&&null!=t&&(F.settings.themes[e]=t),delete F.vars.cache.themeKeys,this},addImage:function(e,t){var n=x.getNodeArray(t);return n.forEach(function(t){var n=x.newEl("img"),r={};r[F.setup.dataAttr]=e,x.setAttr(n,r),t.appendChild(n)}),this},setResizeUpdate:function(e,t){e.holderData&&(e.holderData.resizeUpdate=!!t,e.holderData.resizeUpdate&&h(e))},run:function(e){e=e||{};var n={},a=T(F.settings,e);F.vars.preempted=!0,F.vars.dataAttr=a.dataAttr||F.setup.dataAttr,n.renderer=a.renderer?a.renderer:F.setup.renderer,-1===F.setup.renderers.join(",").indexOf(n.renderer)&&(n.renderer=F.setup.supportsSVG?"svg":F.setup.supportsCanvas?"canvas":"html");var s=x.getNodeArray(a.images),l=x.getNodeArray(a.bgnodes),h=x.getNodeArray(a.stylenodes),u=x.getNodeArray(a.objects);return n.stylesheets=[],n.svgXMLStylesheet=!0,n.noFontFallback=a.noFontFallback?a.noFontFallback:!1,h.forEach(function(e){if(e.attributes.rel&&e.attributes.href&&"stylesheet"==e.attributes.rel.value){var t=e.attributes.href.value,r=x.newEl("a");r.href=t;var i=r.protocol+"//"+r.host+r.pathname+r.search;n.stylesheets.push(i)}}),l.forEach(function(e){if(t.getComputedStyle){var r=t.getComputedStyle(e,null).getPropertyValue("background-image"),s=e.getAttribute("data-background-src"),l=s||r,h=null,u=a.domain+"/",d=l.indexOf(u);if(0===d)h=l;else if(1===d&&"?"===l[0])h=l.slice(1);else{var c=l.substr(d).match(/([^\"]*)"?\)/);if(null!==c)h=c[1];else if(0===l.indexOf("url("))throw"Holder: unable to parse background URL: "+l}if(null!=h){var f=i(h,a);f&&o({mode:"background",el:e,flags:f,engineSettings:n})}}}),u.forEach(function(e){var t={};try{t.data=e.getAttribute("data"),t.dataSrc=e.getAttribute(F.vars.dataAttr)}catch(i){}var o=null!=t.data&&0===t.data.indexOf(a.domain),s=null!=t.dataSrc&&0===t.dataSrc.indexOf(a.domain);o?r(a,n,t.data,e):s&&r(a,n,t.dataSrc,e)}),s.forEach(function(e){var t={};try{t.src=e.getAttribute("src"),t.dataSrc=e.getAttribute(F.vars.dataAttr),t.rendered=e.getAttribute("data-holder-rendered")}catch(i){}var o=null!=t.src,s=null!=t.dataSrc&&0===t.dataSrc.indexOf(a.domain),l=null!=t.rendered&&"true"==t.rendered;o?0===t.src.indexOf(a.domain)?r(a,n,t.src,e):s&&(l?r(a,n,t.dataSrc,e):!function(e,t,n,i,o){w.imageExists(e,function(e){e||r(t,n,i,o)})}(t.src,a,n,t.dataSrc,e)):s&&r(a,n,t.dataSrc,e)}),this}},F={settings:{domain:"holder.js",images:"img",objects:"object",bgnodes:"body .holderjs",stylenodes:"head link.holderjs",themes:{gray:{bg:"#EEEEEE",fg:"#AAAAAA"},social:{bg:"#3a5a97",fg:"#FFFFFF"},industrial:{bg:"#434A52",fg:"#C2F200"},sky:{bg:"#0D8FDB",fg:"#FFFFFF"},vine:{bg:"#39DBAC",fg:"#1E292C"},lava:{bg:"#F8591A",fg:"#1C2846"}}},defaults:{size:10,units:"pt",scale:1/16}},z=function(){var e=null,t=null,n=null;return function(r){var i=r.root;if(F.setup.supportsSVG){var o=!1,a=function(e){return document.createTextNode(e)};(null==e||e.parentNode!==document.body)&&(o=!0),e=b.initSVG(e,i.properties.width,i.properties.height),e.style.display="block",o&&(t=x.newEl("text",j),n=a(null),x.setAttr(t,{x:0}),t.appendChild(n),e.appendChild(t),document.body.appendChild(e),e.style.visibility="hidden",e.style.position="absolute",e.style.top="-100%",e.style.left="-100%");var s=i.children.holderTextGroup,l=s.properties;x.setAttr(t,{y:l.font.size,style:w.cssProps({"font-weight":l.font.weight,"font-size":l.font.size+l.font.units,"font-family":l.font.family})}),n.nodeValue=l.text;var h=t.getBBox(),u=Math.ceil(h.width/i.properties.width),d=l.text.split(" "),c=l.text.match(/\\n/g);u+=null==c?0:c.length,n.nodeValue=l.text.replace(/[ ]+/g,"");var f=t.getComputedTextLength(),p=h.width-f,g=Math.round(p/Math.max(1,d.length-1)),m=[];if(u>1){n.nodeValue="";for(var v=0;v=0?t:1)}function o(e){x?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function C(){document.removeEventListener("DOMContentLoaded",C,!1),document.readyState="complete"},!1),document.readyState="loading");var a=e.document,s=a.documentElement,l="load",h=!1,u="on"+l,d="complete",c="readyState",f="attachEvent",p="detachEvent",g="addEventListener",m="DOMContentLoaded",v="onreadystatechange",y="removeEventListener",w=g in a,b=h,x=h,S=[];if(a[c]===d)i(t);else if(w)a[g](m,n,h),e[g](l,n,h);else{a[f](v,n),e[f](u,n);try{b=null==e.frameElement&&s}catch(A){}b&&b.doScroll&&!function E(){if(!x){try{b.doScroll("left")}catch(e){return i(E,50)}r(),t()}}()}return o.version="1.4.0",o.isReady=function(){return x},o}e.exports="undefined"!=typeof window&&n(window)},function(e,t,n){var r=encodeURIComponent,i=decodeURIComponent,o=n(4),a=n(5),s=/(\w+)\[(\d+)\]/,l=/\w+\.\w+/;t.parse=function(e){if("string"!=typeof e)return{};if(e=o(e),""===e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t={},n=e.split("&"),r=0;r=0;r--)n=e.charCodeAt(r),n>128?t.unshift(["&#",n,";"].join("")):t.unshift(e[r]);return t.join("")},t.imageExists=function(e,t){var n=new Image;n.onerror=function(){t.call(this,!1)},n.onload=function(){t.call(this,!0)},n.src=e},t.decodeHtmlEntity=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})},t.dimensionCheck=function(e){var t={height:e.clientHeight,width:e.clientWidth};return t.height&&t.width?t:!1},t.truthy=function(e){return"string"==typeof e?"true"===e||"yes"===e||"1"===e||"on"===e||"✓"===e:!!e},t.parseColor=function(e){var t,n=/(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i,r=/^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/,i=/^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0\.\d{1,}|1)\)$/,o=e.match(n);return null!==o?(t=o[1]||o[2],"#"!==t[0]?"#"+t:t):(o=e.match(r),null!==o?t="rgb("+o.slice(1).join(",")+")":(o=e.match(i),null!==o?t="rgba("+o.slice(1).join(",")+")":null))},t.canvasRatio=function(){var t=1,n=1;if(e.document){var r=e.document.createElement("canvas");if(r.getContext){var i=r.getContext("2d");t=e.devicePixelRatio||1,n=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1}}return t/n}}).call(t,function(){return this}())},function(e,t,n){(function(e){var r=n(9),i="http://www.w3.org/2000/svg",o=8;t.initSVG=function(e,t,n){var a,s,l=!1;e&&e.querySelector?(s=e.querySelector("style"),null===s&&(l=!0)):(e=r.newEl("svg",i),l=!0),l&&(a=r.newEl("defs",i),s=r.newEl("style",i),r.setAttr(s,{type:"text/css"}),a.appendChild(s),e.appendChild(a)),e.webkitMatchesSelector&&e.setAttribute("xmlns",i);for(var h=0;h=0;l--){var h=s.createProcessingInstruction("xml-stylesheet",'href="'+a[l]+'" rel="stylesheet"');s.insertBefore(h,s.firstChild)}s.removeChild(s.documentElement),o=i.serializeToString(s)}var u=i.serializeToString(t);return u=u.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),o+u}}}).call(t,function(){return this}())},function(e,t){(function(e){t.newEl=function(t,n){return e.document?null==n?e.document.createElement(t):e.document.createElementNS(n,t):void 0},t.setAttr=function(e,t){for(var n in t)e.setAttribute(n,t[n])},t.createXML=function(){return e.DOMParser?(new DOMParser).parseFromString("","application/xml"):void 0},t.getNodeArray=function(t){var n=null;return"string"==typeof t?n=document.querySelectorAll(t):e.NodeList&&t instanceof e.NodeList?n=t:e.Node&&t instanceof e.Node?n=[t]:e.HTMLCollection&&t instanceof e.HTMLCollection?n=t:t instanceof Array?n=t:null===t&&(n=[]),n=Array.prototype.slice.call(n)}}).call(t,function(){return this}())},function(e,t){var n=function(e,t){"string"==typeof e&&(this.original=e,"#"===e.charAt(0)&&(e=e.slice(1)),/[^a-f0-9]+/i.test(e)||(3===e.length&&(e=e.replace(/./g,"$&$&")),6===e.length&&(this.alpha=1,t&&t.alpha&&(this.alpha=t.alpha),this.set(parseInt(e,16)))))};n.rgb2hex=function(e,t,n){function r(e){var t=(0|e).toString(16);return 16>e&&(t="0"+t),t}return[e,t,n].map(r).join("")},n.hsl2rgb=function(e,t,n){var r=e/60,i=(1-Math.abs(2*n-1))*t,o=i*(1-Math.abs(parseInt(r)%2-1)),a=n-i/2,s=0,l=0,h=0;return r>=0&&1>r?(s=i,l=o):r>=1&&2>r?(s=o,l=i):r>=2&&3>r?(l=i,h=o):r>=3&&4>r?(l=o,h=i):r>=4&&5>r?(s=o,h=i):r>=5&&6>r&&(s=i,h=o),s+=a,l+=a,h+=a,s=parseInt(255*s),l=parseInt(255*l),h=parseInt(255*h),[s,l,h]},n.prototype.set=function(e){this.raw=e;var t=(16711680&this.raw)>>16,n=(65280&this.raw)>>8,r=255&this.raw,i=.2126*t+.7152*n+.0722*r,o=-.09991*t-.33609*n+.436*r,a=.615*t-.55861*n-.05639*r;return this.rgb={r:t,g:n,b:r},this.yuv={y:i,u:o,v:a},this},n.prototype.lighten=function(e){var t=Math.min(1,Math.max(0,Math.abs(e)))*(0>e?-1:1),r=255*t|0,i=Math.min(255,Math.max(0,this.rgb.r+r)),o=Math.min(255,Math.max(0,this.rgb.g+r)),a=Math.min(255,Math.max(0,this.rgb.b+r)),s=n.rgb2hex(i,o,a);return new n(s)},n.prototype.toHex=function(e){return(e?"#":"")+this.raw.toString(16)},n.prototype.lighterThan=function(e){return e instanceof n||(e=new n(e)),this.yuv.y>e.yuv.y},n.prototype.blendAlpha=function(e){e instanceof n||(e=new n(e));var t=e,r=this,i=t.alpha*t.rgb.r+(1-t.alpha)*r.rgb.r,o=t.alpha*t.rgb.g+(1-t.alpha)*r.rgb.g,a=t.alpha*t.rgb.b+(1-t.alpha)*r.rgb.b;return new n(n.rgb2hex(i,o,a))},e.exports=n},function(e,t){e.exports={version:"2.9.0",svg_ns:"http://www.w3.org/2000/svg"}},function(e,t,n){function r(e,t){return d.element({tag:t,width:e.width,height:e.height,fill:e.properties.fill})}function i(e){return h.cssProps({fill:e.fill,"font-weight":e.font.weight,"font-family":e.font.family+", monospace","font-size":e.font.size+e.font.units})}function o(e,t,n){var r=n/2;return["M",r,r,"H",e-r,"V",t-r,"H",r,"V",0,"M",0,r,"L",e,t-r,"M",0,t-r,"L",e,r].join(" ")}var a=n(13),s=n(8),l=n(11),h=n(7),u=l.svg_ns,d={element:function(e){var t=e.tag,n=e.content||"";return delete e.tag,delete e.content,[t,n,e]}};e.exports=function(e,t){var n=t.engineSettings,l=n.stylesheets,h=l.map(function(e){return''}).join("\n"),c="holder_"+Number(new Date).toString(16),f=e.root,p=f.children.holderTextGroup,g="#"+c+" text { "+i(p.properties)+" } ";p.y+=.8*p.textPositionData.boundingBox.height;var m=[];Object.keys(p.children).forEach(function(e){var t=p.children[e];Object.keys(t.children).forEach(function(e){var n=t.children[e],r=p.x+t.x+n.x,i=p.y+t.y+n.y,o=d.element({tag:"text",content:n.properties.text,x:r,y:i});m.push(o)})});var v=d.element({tag:"g",content:m}),y=null;if(f.children.holderBg.properties.outline){var w=f.children.holderBg.properties.outline;y=d.element({tag:"path",d:o(f.children.holderBg.width,f.children.holderBg.height,w.width),"stroke-width":w.width,stroke:w.fill,fill:"none"})}var b=r(f.children.holderBg,"rect"),x=[];x.push(b),w&&x.push(y),x.push(v);var S=d.element({tag:"g",id:c,content:x}),A=d.element({tag:"style",content:g,type:"text/css"}),C=d.element({tag:"defs",content:A}),E=d.element({tag:"svg",content:[C,S],width:f.properties.width,height:f.properties.height,xmlns:u,viewBox:[0,0,f.properties.width,f.properties.height].join(" "),preserveAspectRatio:"none"}),T=a(E);T=h+T[0];var k=s.svgStringToDataURI(T,"background"===t.mode);return k}},function(e,t,n){n(14);e.exports=function r(e,t,n){"use strict";function i(e){var t=e.match(/^\w+/),r={tag:t?t[0]:"div",attr:{},children:[]},i=e.match(/#([\w-]+)/),o=e.match(/\$([\w-]+)/),a=e.match(/\.[\w-]+/g);return i&&(r.attr.id=i[1],n[i[1]]=r),o&&(n[o[1]]=r),a&&(r.attr["class"]=a.join(" ").replace(/\./g,"")),e.match(/&$/g)&&(f=!1),r}function o(e,t){return null!==t&&t!==!1&&void 0!==t?"string"!=typeof t&&"object"!=typeof t?String(t):t:void 0}function a(e){return String(e).replace(/&/g,"&").replace(/"/g,""")}function s(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}var l,h,u,d,c=1,f=!0;if(n=n||{},"string"==typeof e[0])e[0]=i(e[0]);else{if(!Array.isArray(e[0]))throw new Error("First element of array must be a string, or an array and not "+JSON.stringify(e[0]));c=0}for(;c",e[0]=l}return n[0]=e[0],u&&u(e[0]),n}},function(e,t){function n(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}e.exports=n},function(e,t,n){var r=n(9),i=n(7);e.exports=function(){var e=r.newEl("canvas"),t=null;return function(n){null==t&&(t=e.getContext("2d"));var r=i.canvasRatio(),o=n.root;e.width=r*o.properties.width,e.height=r*o.properties.height,t.textBaseline="middle";var a=o.children.holderBg,s=r*a.width,l=r*a.height,h=2,u=h/2;t.fillStyle=a.properties.fill,t.fillRect(0,0,s,l),a.properties.outline&&(t.strokeStyle=a.properties.outline.fill,t.lineWidth=a.properties.outline.width,t.moveTo(u,u),t.lineTo(s-u,u),t.lineTo(s-u,l-u),t.lineTo(u,l-u),t.lineTo(u,u),t.moveTo(0,u),t.lineTo(s,l-u),t.moveTo(0,l-u),t.lineTo(s,u),t.stroke());var d=o.children.holderTextGroup;t.font=d.properties.font.weight+" "+r*d.properties.font.size+d.properties.font.units+" "+d.properties.font.family+", monospace",t.fillStyle=d.properties.fill;for(var c in d.children){var f=d.children[c];for(var p in f.children){var g=f.children[p],m=r*(d.x+f.x+g.x),v=r*(d.y+f.y+g.y+d.properties.leading/2);t.fillText(g.properties.text,m,v)}}return e.toDataURL("image/png")}}()}])}),function(e,t){t&&(Holder=e.Holder)}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package); -------------------------------------------------------------------------------- /src/main/resources/static/base/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.5 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); --------------------------------------------------------------------------------