更新框架基础文件
parent
e711199666
commit
01a88e72d7
|
@ -48,6 +48,17 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--Lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
@ -107,6 +118,11 @@
|
|||
<version>3.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -17,10 +17,8 @@ public class BlogController {
|
|||
@Autowired
|
||||
private BlogService blogService;
|
||||
|
||||
@GetMapping("/hello")
|
||||
@GetMapping
|
||||
String blog() {
|
||||
String hello = blogService.hello();
|
||||
System.out.println(hello);
|
||||
return "client/blog/index";
|
||||
}
|
||||
|
||||
|
|
|
@ -5,5 +5,4 @@ package com.songpeng.blog.service;
|
|||
*/
|
||||
public interface BlogService {
|
||||
|
||||
String hello();
|
||||
}
|
||||
|
|
|
@ -5,13 +5,10 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
/**
|
||||
* Controller
|
||||
* Created by songpeng on 2019/5/21.
|
||||
* @author songpeng
|
||||
* @date 2019/5/21
|
||||
*/
|
||||
@Service
|
||||
public class BlogServiceImpl implements BlogService {
|
||||
|
||||
@Override
|
||||
public String hello() {
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
@ControllerAdvice
|
||||
public class ApiAdvice {
|
||||
|
||||
public static final Logger logger = LoggerFactory.getLogger(ApiAdvice.class);
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(ApiAdvice.class);
|
||||
|
||||
/**
|
||||
* 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
|
||||
|
@ -65,7 +65,7 @@ public class ApiAdvice {
|
|||
@ExceptionHandler(Exception.class)
|
||||
@ResponseBody
|
||||
public ApiResponse handle(HttpServletRequest request, Exception e) throws Exception {
|
||||
logger.error("API接口调用异常: {}", request.getRequestURI(), e);
|
||||
LOGGER.error("API接口调用异常: {}", request.getRequestURI(), e);
|
||||
return ApiResponse.error(ApiResponse.ERROR_CODE, ApiResponse.ERROR_MSG);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package com.songpeng.common.config;
|
||||
|
||||
import com.songpeng.system.service.impl.SysUserServiceImpl;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/**
|
||||
* Controller
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/5/23
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
UserDetailsService customUserService() { //注册UserDetailsService 的bean
|
||||
return new SysUserServiceImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// user Details Service验证
|
||||
auth.userDetailsService(customUserService());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// TODO 1. csrf 暂时关闭
|
||||
http.authorizeRequests().anyRequest().permitAll().and().csrf().disable();
|
||||
// .anyRequest().authenticated() //任何请求,登录后可以访问
|
||||
// .and()
|
||||
// .formLogin()
|
||||
// .loginPage("/login")
|
||||
// .failureUrl("/login?error")
|
||||
// .permitAll() //登录页面用户任意访问
|
||||
// .and()
|
||||
// .logout().permitAll(); //注销行为任意访问
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package com.songpeng.common.utils;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* ByteUtil
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/5/23
|
||||
*/
|
||||
public class ByteUtil {
|
||||
|
||||
/**
|
||||
* Join two byte arrays to a new byte array.
|
||||
*/
|
||||
public static byte[] concat(byte[] buf1, byte[] buf2) {
|
||||
byte[] buffer = new byte[buf1.length + buf2.length];
|
||||
int offset = 0;
|
||||
System.arraycopy(buf1, 0, buffer, offset, buf1.length);
|
||||
offset += buf1.length;
|
||||
System.arraycopy(buf2, 0, buffer, offset, buf2.length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join three byte arrays to a new byte array.
|
||||
*/
|
||||
public static byte[] concat(byte[] buf1, byte[] buf2, byte[] buf3) {
|
||||
byte[] buffer = new byte[buf1.length + buf2.length + buf3.length];
|
||||
int offset = 0;
|
||||
System.arraycopy(buf1, 0, buffer, offset, buf1.length);
|
||||
offset += buf1.length;
|
||||
System.arraycopy(buf2, 0, buffer, offset, buf2.length);
|
||||
offset += buf2.length;
|
||||
System.arraycopy(buf3, 0, buffer, offset, buf3.length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert bytes to hex string (all lower-case).
|
||||
*
|
||||
* @param b Input bytes.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String toHexString(byte[] b) {
|
||||
StringBuilder sb = new StringBuilder(b.length * 2);
|
||||
for (byte x : b) {
|
||||
int hi = (x & 0xf0) >> 4;
|
||||
int lo = x & 0x0f;
|
||||
sb.append(HEX_CHARS[hi]);
|
||||
sb.append(HEX_CHARS[lo]);
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert byte to hex string (all lower-case).
|
||||
*
|
||||
* @param b Input bytes.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String toHex(byte b) {
|
||||
int hi = (b & 0xf0) >> 4;
|
||||
int lo = b & 0x0f;
|
||||
char[] cs = { HEX_CHARS[hi], HEX_CHARS[lo] };
|
||||
return new String(cs);
|
||||
}
|
||||
|
||||
public static byte fromHex(String s) {
|
||||
if (s.length() != 2) {
|
||||
throw new IllegalArgumentException("Invalid length of string.");
|
||||
}
|
||||
char c1 = s.charAt(0);
|
||||
char c2 = s.charAt(1);
|
||||
int n1 = HEX_STRING.indexOf(c1);
|
||||
int n2 = HEX_STRING.indexOf(c2);
|
||||
if (n1 == (-1)) {
|
||||
throw new IllegalArgumentException("Invalid char in string: " + c1);
|
||||
}
|
||||
if (n2 == (-1)) {
|
||||
throw new IllegalArgumentException("Invalid char in string: " + c2);
|
||||
}
|
||||
int n = (n1 << 4) + n2;
|
||||
return (byte) n;
|
||||
}
|
||||
|
||||
public static byte[] fromHexString(String s) {
|
||||
if (s.length() % 2 == 1) {
|
||||
throw new IllegalArgumentException("Invalid length of string.");
|
||||
}
|
||||
byte[] data = new byte[s.length() / 2];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
char c1 = s.charAt(i * 2);
|
||||
char c2 = s.charAt(i * 2 + 1);
|
||||
int n1 = HEX_STRING.indexOf(c1);
|
||||
int n2 = HEX_STRING.indexOf(c2);
|
||||
if (n1 == (-1)) {
|
||||
throw new IllegalArgumentException("Invalid char in string: " + c1);
|
||||
}
|
||||
if (n2 == (-1)) {
|
||||
throw new IllegalArgumentException("Invalid char in string: " + c2);
|
||||
}
|
||||
int n = (n1 << 4) + n2;
|
||||
data[i] = (byte) n;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static boolean isSha1(String s) {
|
||||
return PATTERN_SHA1.matcher(s).matches();
|
||||
}
|
||||
|
||||
public static boolean isSha256(String s) {
|
||||
return PATTERN_SHA256.matcher(s).matches();
|
||||
}
|
||||
|
||||
private static final String HEX_STRING = "0123456789abcdef";
|
||||
private static final char[] HEX_CHARS = HEX_STRING.toCharArray();
|
||||
|
||||
private static final Pattern PATTERN_SHA1 = Pattern.compile("^[a-f0-9]{40}$");
|
||||
private static final Pattern PATTERN_SHA256 = Pattern.compile("^[a-f0-9]{64}$");
|
||||
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
package com.songpeng.common.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Utility class for hashing.
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/5/23
|
||||
*/
|
||||
public class HashUtil {
|
||||
|
||||
/**
|
||||
* Generate SHA-1 as hex string (all lower-case).
|
||||
*
|
||||
* @param input Input as string.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String sha1(String input) {
|
||||
return sha1(input.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-1 as hex string (all lower-case).
|
||||
*
|
||||
* @param input Input as bytes.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String sha1(byte[] input) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
md.update(input);
|
||||
byte[] digest = md.digest();
|
||||
return ByteUtil.toHexString(digest);
|
||||
}
|
||||
|
||||
public static byte[] sha1AsBytes(String input) {
|
||||
return sha1AsBytes(input.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-1 as bytes.
|
||||
*
|
||||
* @param input Input as bytes.
|
||||
* @return Bytes.
|
||||
*/
|
||||
public static byte[] sha1AsBytes(byte[] input) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
md.update(input);
|
||||
return md.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-256 as hex string (all lower-case).
|
||||
*
|
||||
* @param input Input as String.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String sha256(String input) {
|
||||
return sha256(input.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-256 as hex string (all lower-case).
|
||||
*
|
||||
* @param input Input as String.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static byte[] sha256AsBytes(String input) {
|
||||
return sha256AsBytes(input.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-256 as hex string (all lower-case).
|
||||
*
|
||||
* @param input Input as bytes.
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String sha256(byte[] input) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
md.update(input);
|
||||
byte[] digest = md.digest();
|
||||
return ByteUtil.toHexString(digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-256 as bytes.
|
||||
*
|
||||
* @param input Input as bytes.
|
||||
* @return SHA bytes.
|
||||
*/
|
||||
public static byte[] sha256AsBytes(byte[] input) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
md.update(input);
|
||||
return md.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate SHA-512 as bytes.
|
||||
*
|
||||
* @param input Input as bytes.
|
||||
* @return SHA bytes.
|
||||
*/
|
||||
public static byte[] sha512AsBytes(byte[] input) {
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA-512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
md.update(input);
|
||||
return md.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do HMAC-SHA256.
|
||||
*
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static byte[] hmacSha256AsBytes(byte[] data, byte[] key) {
|
||||
SecretKey skey = new SecretKeySpec(key, "HmacSHA256");
|
||||
Mac mac;
|
||||
try {
|
||||
mac = Mac.getInstance("HmacSHA256");
|
||||
mac.init(skey);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mac.update(data);
|
||||
return mac.doFinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do HMAC-SHA256.
|
||||
*
|
||||
* @return Hex string.
|
||||
*/
|
||||
public static String hmacSha256(byte[] data, byte[] key) {
|
||||
return ByteUtil.toHexString(hmacSha256AsBytes(data, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do HMAC-SHA1.
|
||||
*
|
||||
* @return byte[] as result.
|
||||
*/
|
||||
public static byte[] hmacSha1(byte[] data, byte[] key) {
|
||||
SecretKey skey = new SecretKeySpec(key, "HmacSHA1");
|
||||
Mac mac;
|
||||
try {
|
||||
mac = Mac.getInstance("HmacSHA1");
|
||||
mac.init(skey);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
mac.update(data);
|
||||
return mac.doFinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do HMAC-SHA256.
|
||||
*
|
||||
* @return byte[] as result.
|
||||
*/
|
||||
public static String hmacSha256(String data, String key) {
|
||||
return hmacSha256(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do HMAC-SHA256.
|
||||
*
|
||||
* @return byte[] as result.
|
||||
*/
|
||||
public static byte[] hmacSha256AsBytes(String data, String key) {
|
||||
return hmacSha256AsBytes(data.getBytes(StandardCharsets.UTF_8), key.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do HMAC-SHA256.
|
||||
*
|
||||
* @return byte[] as result.
|
||||
*/
|
||||
public static String hmacSha256(byte[] data, String key) {
|
||||
return hmacSha256(data, key.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package com.songpeng.common.utils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 53 bits unique id:
|
||||
*
|
||||
* |--------|--------|--------|--------|--------|--------|--------|--------|
|
||||
* |00000000|00011111|11111111|11111111|11111111|11111111|11111111|11111111|
|
||||
* |--------|---xxxxx|xxxxxxxx|xxxxxxxx|xxxxxxxx|xxx-----|--------|--------|
|
||||
* |--------|--------|--------|--------|--------|---xxxxx|xxxxxxxx|xxx-----|
|
||||
* |--------|--------|--------|--------|--------|--------|--------|---xxxxx|
|
||||
*
|
||||
* Maximum ID = 11111_11111111_11111111_11111111_11111111_11111111_11111111
|
||||
*
|
||||
* Maximum TS = 11111_11111111_11111111_11111111_111
|
||||
*
|
||||
* Maximum NT = ----- -------- -------- -------- ---11111_11111111_111 = 65535
|
||||
*
|
||||
* Maximum SH = ----- -------- -------- -------- -------- -------- ---11111 = 31
|
||||
*
|
||||
* It can generate 64k unique id per IP and up to 2106-02-07T06:28:15Z.
|
||||
*
|
||||
* 时间戳减去一个固定值,此方案最高可支持到2106年。
|
||||
*
|
||||
* 如果每秒65万个序列号不够怎么办?没关系,可以继续递增时间戳,向前“借”下一秒的65万个序列号。
|
||||
*
|
||||
* 同时还解决了时间回拨的问题。
|
||||
*
|
||||
* 机器标识采用简单的主机名方案,只要主机名符合host-1,host-2就可以自动提取机器标识,无需配置。
|
||||
*
|
||||
* 最后,为什么采用最多53位整型,而不是64位整型?这是因为考虑到大部分应用程序是Web应用,
|
||||
* 如果要和JavaScript打交道,由于JavaScript支持的最大整型就是53位,超过这个位数,JavaScript将丢失精度。
|
||||
* 因此,使用53位整数可以直接由JavaScript读取,而超过53位时,就必须转换成字符串才能保证JavaScript处理正确,
|
||||
* 这会给API接口带来额外的复杂度。这也是为什么新浪微博的API接口会同时返回id和idstr的原因。
|
||||
*
|
||||
* 参考链接:https://mp.weixin.qq.com/s/C6QkzzUMPiYov8GO8zJTLA
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/05/23
|
||||
*/
|
||||
public final class IdUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IdUtil.class);
|
||||
|
||||
private static final Pattern PATTERN_LONG_ID = Pattern.compile("^([0-9]{15})([0-9a-f]{32})([0-9a-f]{3})$");
|
||||
|
||||
private static final Pattern PATTERN_HOSTNAME = Pattern.compile("^.*\\D+([0-9]+)$");
|
||||
|
||||
private static final long OFFSET = LocalDate.of(2000, 1, 1).atStartOfDay(ZoneId.of("Z")).toEpochSecond();
|
||||
|
||||
private static final long MAX_NEXT = 0b11111_11111111_111L;
|
||||
|
||||
private static final long SHARD_ID = getServerIdAsLong();
|
||||
|
||||
private static long offset = 0;
|
||||
|
||||
private static long lastEpoch = 0;
|
||||
|
||||
public static long nextId() {
|
||||
return nextId(System.currentTimeMillis() / 1000);
|
||||
}
|
||||
|
||||
private static synchronized long nextId(long epochSecond) {
|
||||
if (epochSecond < lastEpoch) {
|
||||
// warning: clock is turn back:
|
||||
LOGGER.warn("clock is back: " + epochSecond + " from previous:" + lastEpoch);
|
||||
epochSecond = lastEpoch;
|
||||
}
|
||||
if (lastEpoch != epochSecond) {
|
||||
lastEpoch = epochSecond;
|
||||
reset();
|
||||
}
|
||||
offset++;
|
||||
long next = offset & MAX_NEXT;
|
||||
if (next == 0) {
|
||||
LOGGER.warn("maximum id reached in 1 second in epoch: " + epochSecond);
|
||||
return nextId(epochSecond + 1);
|
||||
}
|
||||
return generateId(epochSecond, next, SHARD_ID);
|
||||
}
|
||||
|
||||
private static void reset() {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
private static long generateId(long epochSecond, long next, long shardId) {
|
||||
return ((epochSecond - OFFSET) << 21) | (next << 5) | shardId;
|
||||
}
|
||||
|
||||
private static long getServerIdAsLong() {
|
||||
try {
|
||||
String hostname = InetAddress.getLocalHost().getHostName();
|
||||
Matcher matcher = PATTERN_HOSTNAME.matcher(hostname);
|
||||
if (matcher.matches()) {
|
||||
long n = Long.parseLong(matcher.group(1));
|
||||
if (n >= 0 && n < 8) {
|
||||
LOGGER.info("detect server id from host name {}: {}.", hostname, n);
|
||||
return n;
|
||||
}
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
LOGGER.warn("unable to get host name. set server id = 0.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long stringIdToLongId(String stringId) {
|
||||
// a stringId id is composed as timestamp (15) + uuid (32) + serverId (000~fff).
|
||||
Matcher matcher = PATTERN_LONG_ID.matcher(stringId);
|
||||
if (matcher.matches()) {
|
||||
long epoch = Long.parseLong(matcher.group(1)) / 1000;
|
||||
String uuid = matcher.group(2);
|
||||
byte[] sha1 = HashUtil.sha1AsBytes(uuid);
|
||||
long next = ((sha1[0] << 24) | (sha1[1] << 16) | (sha1[2] << 8) | sha1[3]) & MAX_NEXT;
|
||||
long serverId = Long.parseLong(matcher.group(3), 16);
|
||||
return generateId(epoch, next, serverId);
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid id: " + stringId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
在应用程序中,经常需要全局唯一的ID作为数据库主键。如何生成全局唯一ID?
|
||||
|
||||
首先,需要确定全局唯一ID是整型还是字符串?如果是字符串,那么现有的UUID就完全满足需求,不需要额外的工作。缺点是字符串作为ID占用空间大,索引效率比整型低。
|
||||
|
||||
如果采用整型作为ID,那么首先排除掉32位int类型,因为范围太小,必须使用64位long型。
|
||||
|
||||
采用整型作为ID时,如何生成自增、全局唯一且不重复的ID?
|
||||
|
||||
方案一:利用数据库的自增ID,从1开始,基本可以做到连续递增。Oracle可以用SEQUENCE,MySQL可以用主键的AUTO_INCREMENT,虽然不能保证全局唯一,但每个表唯一,也基本满足需求。
|
||||
|
||||
数据库自增ID的缺点是数据在插入前,无法获得ID。数据在插入后,获取的ID虽然是唯一的,但一定要等到事务提交后,ID才算是有效的。有些双向引用的数据,不得不插入后再做一次更新,比较麻烦。
|
||||
|
||||
第二种方式是采用一个集中式ID生成器,它可以是Redis,也可以是ZooKeeper,也可以利用数据库的表记录最后分配的ID。
|
||||
|
||||
这种方式最大的缺点是复杂性太高,需要严重依赖第三方服务,而且代码配置繁琐。一般来说,越是复杂的方案,越不可靠,并且测试越痛苦。
|
||||
|
||||
第三种方式是类似Twitter的Snowflake算法,它给每台机器分配一个唯一标识,然后通过时间戳+标识+自增实现全局唯一ID。这种方式好处在于ID生成算法完全是一个无状态机,无网络调用,高效可靠。缺点是如果唯一标识有重复,会造成ID冲突。
|
||||
|
||||
Snowflake算法采用41bit毫秒时间戳,加上10bit机器ID,加上12bit序列号,理论上最多支持1024台机器每秒生成4096000个序列号,对于Twitter的规模来说够用了。
|
||||
|
||||
但是对于绝大部分普通应用程序来说,根本不需要每秒超过400万的ID,机器数量也达不到1024台,所以,我们可以改进一下,使用更短的ID生成方式:
|
||||
|
||||
53bitID由32bit秒级时间戳+16bit自增+5bit机器标识组成,累积32台机器,每秒可以生成65万个序列号,核心代码:
|
||||
|
||||
private static synchronized long nextId(long epochSecond) {
|
||||
if (epochSecond < lastEpoch) {
|
||||
// warning: clock is turn back:
|
||||
logger.warn("clock is back: " + epochSecond + " from previous:" + lastEpoch);
|
||||
epochSecond = lastEpoch;
|
||||
}
|
||||
if (lastEpoch != epochSecond) {
|
||||
lastEpoch = epochSecond;
|
||||
reset();
|
||||
}
|
||||
offset++;
|
||||
long next = offset & MAX_NEXT;
|
||||
if (next == 0) {
|
||||
logger.warn("maximum id reached in 1 second in epoch: " + epochSecond);
|
||||
return nextId(epochSecond + 1);
|
||||
}
|
||||
return generateId(epochSecond, next, SHARD_ID);
|
||||
}
|
||||
时间戳减去一个固定值,此方案最高可支持到2106年。
|
||||
|
||||
如果每秒65万个序列号不够怎么办?没关系,可以继续递增时间戳,向前“借”下一秒的65万个序列号。
|
||||
|
||||
同时还解决了时间回拨的问题。
|
||||
|
||||
机器标识采用简单的主机名方案,只要主机名符合host-1,host-2就可以自动提取机器标识,无需配置。
|
||||
|
||||
最后,为什么采用最多53位整型,而不是64位整型?这是因为考虑到大部分应用程序是Web应用,如果要和JavaScript打交道,由于JavaScript支持的最大整型就是53位,超过这个位数,JavaScript将丢失精度。因此,使用53位整数可以直接由JavaScript读取,而超过53位时,就必须转换成字符串才能保证JavaScript处理正确,这会给API接口带来额外的复杂度。这也是为什么新浪微博的API接口会同时返回id和idstr的原因。
|
||||
*/
|
||||
package com.songpeng.common.utils;
|
|
@ -0,0 +1,52 @@
|
|||
package com.songpeng.system.controller.admin;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.songpeng.common.utils.ApiResponse;
|
||||
import com.songpeng.common.utils.PageRequest;
|
||||
import com.songpeng.system.domain.SysUser;
|
||||
import com.songpeng.system.dto.SysUserDto;
|
||||
import com.songpeng.system.service.SysUserService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户 Controller
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019-04-19
|
||||
*/
|
||||
@RequestMapping("/admin/sys/user")
|
||||
@Controller("adminUserController")
|
||||
public class SysUserController {
|
||||
|
||||
/**
|
||||
* 日志记录器
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SysUserController.class);
|
||||
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@RequestMapping("/page")
|
||||
@ResponseBody
|
||||
public ApiResponse getPage(PageRequest pageRequest) {
|
||||
LOGGER.info("获取用户列表");
|
||||
PageInfo<SysUserDto> pageInfo = sysUserService.getPage(pageRequest);
|
||||
Map<String, Object> result = new HashMap<>(1);
|
||||
result.put("result", pageInfo);
|
||||
return ApiResponse.ok(result);
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@ResponseBody
|
||||
public ApiResponse add(SysUser sysUser, String[] roles) {
|
||||
sysUserService.add(sysUser, roles);
|
||||
return ApiResponse.ok();
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package com.songpeng.system.controller.admin;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.songpeng.common.utils.ApiResponse;
|
||||
import com.songpeng.common.utils.PageRequest;
|
||||
import com.songpeng.system.domain.User;
|
||||
import com.songpeng.system.service.UserService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户 Controller
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019-04-19
|
||||
*/
|
||||
@RequestMapping("/admin/sys/user")
|
||||
@Controller("adminUserController")
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* 日志记录器
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
|
||||
|
||||
@RequestMapping("/page")
|
||||
@ResponseBody
|
||||
public ApiResponse getPage(PageRequest pageRequest) {
|
||||
logger.info("获取用户列表");
|
||||
PageInfo<User> pageInfo = userService.getPage(pageRequest);
|
||||
Map<String, Object> res = new HashMap<>(2);
|
||||
res.put("result", pageInfo);
|
||||
return ApiResponse.ok(res);
|
||||
}
|
||||
|
||||
}
|
|
@ -31,4 +31,34 @@ public class LoginController {
|
|||
return "redirect:/blog";
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问后台管理系统首页
|
||||
*
|
||||
* @param model
|
||||
* @return
|
||||
*/
|
||||
@GetMapping({"/index"})
|
||||
String index(Model model) {
|
||||
// List<Tree<MenuDO>> menus = menuService.listMenuTree(getUserId());
|
||||
// model.addAttribute("menus", menus);
|
||||
// model.addAttribute("name", getUser().getName());
|
||||
// FileDO fileDO = fileService.get(getUser().getPicId());
|
||||
// if (fileDO != null && fileDO.getUrl() != null) {
|
||||
// if (fileService.isExist(fileDO.getUrl())) {
|
||||
// model.addAttribute("picUrl", fileDO.getUrl());
|
||||
// } else {
|
||||
// model.addAttribute("picUrl", "/img/photo_s.jpg");
|
||||
// }
|
||||
// } else {
|
||||
// model.addAttribute("picUrl", "/img/photo_s.jpg");
|
||||
// }
|
||||
// model.addAttribute("username", getUser().getUsername());
|
||||
return "admin/index";
|
||||
}
|
||||
|
||||
@GetMapping("/main")
|
||||
String main() {
|
||||
return "admin/main";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.songpeng.system.domain;
|
||||
|
||||
/**
|
||||
* 系统角色
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/5/23
|
||||
*/
|
||||
public class SysRole {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("SysRole{");
|
||||
sb.append("id=").append(id);
|
||||
sb.append(", name='").append(name).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.songpeng.system.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 系统用户
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/05/21
|
||||
*/
|
||||
@Table(name = "SYS_USER")
|
||||
public class SysUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -583330206794726157L;
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
@Column(name = "NAME")
|
||||
private String name;
|
||||
@Column(name = "USERNAME")
|
||||
private String username;
|
||||
@Column(name = "PASSWORD")
|
||||
private String password;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("SysUser{");
|
||||
sb.append("id=").append(id);
|
||||
sb.append(", name='").append(name).append('\'');
|
||||
sb.append(", username='").append(username).append('\'');
|
||||
sb.append(", password='").append(password).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package com.songpeng.system.domain;
|
||||
|
||||
/**
|
||||
* Controller
|
||||
* Created by songpeng on 2019/5/21.
|
||||
*/
|
||||
public class User {
|
||||
private String id;
|
||||
private String name;
|
||||
private String username;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("User{");
|
||||
sb.append("id='").append(id).append('\'');
|
||||
sb.append(", name='").append(name).append('\'');
|
||||
sb.append(", username='").append(username).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.songpeng.system.dto;
|
||||
|
||||
import com.songpeng.system.domain.SysRole;
|
||||
import com.songpeng.system.domain.SysUser;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统用户 dto
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/5/23
|
||||
*/
|
||||
public class SysUserDto extends SysUser implements UserDetails {
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
// List<RoleGrantedAuthority> authorityList = new ArrayList<>();
|
||||
// authorityList.add(new RoleGrantedAuthority("ROLE_USER"));
|
||||
//
|
||||
// // 加入角色权限
|
||||
// if (roleList != null && !roleList.isEmpty()) {
|
||||
// for (SysRole role : roleList) {
|
||||
// if (StringUtils.isNotBlank(role.getCode())) {
|
||||
// authorityList.add(new RoleGrantedAuthority("ROLE_" + role.getCode().toUpperCase()));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return authorityList;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户是否过期,过期无法验证
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定用户是否被锁定或者解锁,锁定的用户无法进行身份验证
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否被禁用,禁用的用户不能身份验证
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.songpeng.system.mapper;
|
||||
|
||||
import com.songpeng.common.utils.SpMapper;
|
||||
import com.songpeng.system.domain.SysUser;
|
||||
import com.songpeng.system.dto.SysUserDto;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface SysUserMapper extends SpMapper<SysUser> {
|
||||
|
||||
List<SysUserDto> getPage(Map<String, Object> params);
|
||||
|
||||
List<SysUserDto> getSysUserDtosRoles(Map<String, Object> paramMap);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.songpeng.system.mapper;
|
||||
|
||||
import com.songpeng.system.domain.User;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mapper
|
||||
public interface UserMapper {
|
||||
|
||||
List<User> getPage(Map<String, Object> params);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.songpeng.system.service;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.songpeng.common.utils.PageRequest;
|
||||
import com.songpeng.system.domain.SysUser;
|
||||
import com.songpeng.system.dto.SysUserDto;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* UserService
|
||||
* @author songpeng
|
||||
* @date 2019/4/20.
|
||||
*/
|
||||
public interface SysUserService {
|
||||
|
||||
/**
|
||||
* 获取用户分页
|
||||
* @param pageRequest
|
||||
* @return
|
||||
*/
|
||||
PageInfo<SysUserDto> getPage(PageRequest pageRequest);
|
||||
|
||||
/**
|
||||
* 获取用户信息(包含权限)
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
SysUserDto getUserDtoRoles(Map<String, Object> paramMap);
|
||||
|
||||
void add(SysUser sysUser, String[] roles);
|
||||
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package com.songpeng.system.service;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.songpeng.common.utils.PageRequest;
|
||||
import com.songpeng.system.domain.User;
|
||||
|
||||
/**
|
||||
* UserService
|
||||
* @author songpeng
|
||||
* @date 2019/4/20.
|
||||
*/
|
||||
public interface UserService {
|
||||
|
||||
/**
|
||||
* 获取用户分页
|
||||
* @param pageRequest
|
||||
* @return
|
||||
*/
|
||||
PageInfo<User> getPage(PageRequest pageRequest);
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.songpeng.system.service.impl;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.songpeng.common.utils.IdUtil;
|
||||
import com.songpeng.common.utils.PageRequest;
|
||||
import com.songpeng.common.utils.StringUtils;
|
||||
import com.songpeng.system.domain.SysUser;
|
||||
import com.songpeng.system.dto.SysUserDto;
|
||||
import com.songpeng.system.mapper.SysUserMapper;
|
||||
import com.songpeng.system.service.SysUserService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* UserServiceImpl
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/4/20
|
||||
*/
|
||||
@Service
|
||||
public class SysUserServiceImpl implements SysUserService, UserDetailsService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SysUserServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
if (StringUtils.isBlank(username)) {
|
||||
throw new BadCredentialsException("用户名不能为空!");
|
||||
}
|
||||
|
||||
// 根据用户名和正常状态获取用户信息
|
||||
Map<String, Object> paraMap = new HashMap(1) {{
|
||||
put("userName", username);
|
||||
}};
|
||||
SysUserDto userDto = getUserDtoRoles(paraMap);
|
||||
|
||||
if (userDto == null) {
|
||||
throw new BadCredentialsException("未找到用户名为 " + username + " 的用户信息");
|
||||
}
|
||||
|
||||
return userDto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<SysUserDto> getPage(PageRequest pageRequest) {
|
||||
// 将参数传给这个方法就可以实现物理分页了
|
||||
PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
|
||||
List<SysUserDto> users = sysUserMapper.getPage(pageRequest.getParams());
|
||||
PageInfo result = new PageInfo(users);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysUserDto getUserDtoRoles(Map<String, Object> paramMap) {
|
||||
List<SysUserDto> userDtos = sysUserMapper.getSysUserDtosRoles(paramMap);
|
||||
return userDtos.isEmpty() ? null : userDtos.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(SysUser sysUser, String[] roles) {
|
||||
sysUser.setId(IdUtil.nextId());
|
||||
LOGGER.info("user insert id: {}", sysUser.getId());
|
||||
sysUserMapper.insertSelective(sysUser);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package com.songpeng.system.service.impl;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.songpeng.common.utils.PageRequest;
|
||||
import com.songpeng.system.domain.User;
|
||||
import com.songpeng.system.mapper.UserMapper;
|
||||
import com.songpeng.system.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* UserServiceImpl
|
||||
*
|
||||
* @author songpeng
|
||||
* @date 2019/4/20
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
@Override
|
||||
public PageInfo<User> getPage(PageRequest pageRequest) {
|
||||
//将参数传给这个方法就可以实现物理分页了,非常简单。
|
||||
PageHelper.startPage(pageRequest.getPageNum(), pageRequest.getPageSize());
|
||||
List<User> users = userMapper.getPage(pageRequest.getParams());
|
||||
PageInfo result = new PageInfo(users);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="com.songpeng.system.mapper.UserMapper" >
|
||||
<select id="getPage" resultType="com.songpeng.system.domain.User">
|
||||
<mapper namespace="com.songpeng.system.mapper.SysUserMapper" >
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.songpeng.system.domain.SysUser" >
|
||||
<result column="ID" jdbcType="VARCHAR" property="id" />
|
||||
<result column="NAME" jdbcType="VARCHAR" property="name" />
|
||||
<result column="USERNAME" jdbcType="VARCHAR" property="username" />
|
||||
<result column="PASSWORD" jdbcType="VARCHAR" property="password" />
|
||||
</resultMap>
|
||||
|
||||
<!-- SysUserRolesDto 返回 -->
|
||||
<resultMap id="SysUserDtoRolesMap" type="com.songpeng.system.dto.SysUserDto" extends="BaseResultMap">
|
||||
<collection property="roleList"
|
||||
ofType="com.tn.iip.zu.system.model.SysRole"
|
||||
column="id"
|
||||
select="com.tn.iip.zu.system.mapper.SysRoleMapper.selectRolesByUserId"/>
|
||||
</resultMap>
|
||||
|
||||
<!--分页查询用户-->
|
||||
<select id="getPage" resultType="com.songpeng.system.dto.SysUserDto">
|
||||
SELECT
|
||||
*
|
||||
t.*
|
||||
FROM
|
||||
sys_user
|
||||
sys_user t
|
||||
</select>
|
||||
|
||||
<!--查询用户列表(包含角色列表)-->
|
||||
<select id="getSysUserDtosRoles" parameterType="java.lang.String" resultMap="SysUserDtoRolesMap">
|
||||
SELECT
|
||||
t.*
|
||||
FROM
|
||||
sys_user t
|
||||
WHERE t.username = #{username}
|
||||
</select>
|
||||
</mapper>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,222 @@
|
|||
.toast-title {
|
||||
font-weight: 700
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
-ms-word-wrap: break-word;
|
||||
word-wrap: break-word
|
||||
}
|
||||
|
||||
.toast-message a, .toast-message label {
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.toast-message a:hover {
|
||||
color: #ccc;
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
.toast-close-button {
|
||||
position: relative;
|
||||
right: -.3em;
|
||||
top: -.3em;
|
||||
float: right;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
-webkit-text-shadow: 0 1px 0 #fff;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
opacity: .8;
|
||||
-ms-filter: alpha(Opacity=80);
|
||||
filter: alpha(opacity=80)
|
||||
}
|
||||
|
||||
.toast-close-button:focus, .toast-close-button:hover {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
opacity: .4;
|
||||
-ms-filter: alpha(Opacity=40);
|
||||
filter: alpha(opacity=40)
|
||||
}
|
||||
|
||||
button.toast-close-button {
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
-webkit-appearance: none
|
||||
}
|
||||
|
||||
.toast-top-center {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.toast-bottom-center {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.toast-top-full-width {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.toast-bottom-full-width {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.toast-top-left {
|
||||
top: 12px;
|
||||
left: 12px
|
||||
}
|
||||
|
||||
.toast-top-right {
|
||||
top: 12px;
|
||||
right: 12px
|
||||
}
|
||||
|
||||
.toast-bottom-right {
|
||||
right: 12px;
|
||||
bottom: 12px
|
||||
}
|
||||
|
||||
.toast-bottom-left {
|
||||
bottom: 12px;
|
||||
left: 12px
|
||||
}
|
||||
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
z-index: 999999
|
||||
}
|
||||
|
||||
#toast-container * {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
#toast-container > div {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 0 0 6px;
|
||||
padding: 15px 15px 15px 50px;
|
||||
width: 300px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background-position: 15px center;
|
||||
background-repeat: no-repeat;
|
||||
-moz-box-shadow: 0 0 12px #999;
|
||||
-webkit-box-shadow: 0 0 12px #999;
|
||||
box-shadow: 0 0 12px #999;
|
||||
color: #fff;
|
||||
opacity: .8;
|
||||
-ms-filter: alpha(Opacity=80);
|
||||
filter: alpha(opacity=80)
|
||||
}
|
||||
|
||||
#toast-container > :hover {
|
||||
-moz-box-shadow: 0 0 12px #000;
|
||||
-webkit-box-shadow: 0 0 12px #000;
|
||||
box-shadow: 0 0 12px #000;
|
||||
opacity: 1;
|
||||
-ms-filter: alpha(Opacity=100);
|
||||
filter: alpha(opacity=100);
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
#toast-container > .toast-info {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=) !important
|
||||
}
|
||||
|
||||
#toast-container > .toast-error {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=) !important
|
||||
}
|
||||
|
||||
#toast-container > .toast-success {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==) !important
|
||||
}
|
||||
|
||||
#toast-container > .toast-warning {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=) !important
|
||||
}
|
||||
|
||||
#toast-container.toast-bottom-center > div, #toast-container.toast-top-center > div {
|
||||
width: 300px;
|
||||
margin: auto
|
||||
}
|
||||
|
||||
#toast-container.toast-bottom-full-width > div, #toast-container.toast-top-full-width > div {
|
||||
width: 96%;
|
||||
margin: auto
|
||||
}
|
||||
|
||||
.toast {
|
||||
background-color: #030303
|
||||
}
|
||||
|
||||
.toast-success {
|
||||
background-color: #51a351
|
||||
}
|
||||
|
||||
.toast-error {
|
||||
background-color: #bd362f
|
||||
}
|
||||
|
||||
.toast-info {
|
||||
background-color: #2f96b4
|
||||
}
|
||||
|
||||
.toast-warning {
|
||||
background-color: #f89406
|
||||
}
|
||||
|
||||
.toast-progress {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 4px;
|
||||
background-color: #000;
|
||||
opacity: .4;
|
||||
-ms-filter: alpha(Opacity=40);
|
||||
filter: alpha(opacity=40)
|
||||
}
|
||||
|
||||
@media all and (max-width: 240px) {
|
||||
#toast-container > div {
|
||||
padding: 8px 8px 8px 50px;
|
||||
width: 11em
|
||||
}
|
||||
|
||||
#toast-container .toast-close-button {
|
||||
right: -.2em;
|
||||
top: -.2em
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 241px) and (max-width: 480px) {
|
||||
#toast-container > div {
|
||||
padding: 8px 8px 8px 50px;
|
||||
width: 18em
|
||||
}
|
||||
|
||||
#toast-container .toast-close-button {
|
||||
right: -.2em;
|
||||
top: -.2em
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 481px) and (max-width: 768px) {
|
||||
#toast-container > div {
|
||||
padding: 15px 15px 15px 50px;
|
||||
width: 25em
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,278 @@
|
|||
//自定义js
|
||||
|
||||
//公共配置
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// MetsiMenu
|
||||
$('#side-menu').metisMenu();
|
||||
|
||||
// 打开右侧边栏
|
||||
$('.right-sidebar-toggle').click(function () {
|
||||
$('#right-sidebar').toggleClass('sidebar-open');
|
||||
});
|
||||
|
||||
// 右侧边栏使用slimscroll
|
||||
$('.sidebar-container').slimScroll({
|
||||
height: '100%',
|
||||
railOpacity: 0.4,
|
||||
wheelStep: 10
|
||||
});
|
||||
|
||||
// 打开聊天窗口
|
||||
$('.open-small-chat').click(function () {
|
||||
$(this).children().toggleClass('fa-comments').toggleClass('fa-remove');
|
||||
$('.small-chat-box').toggleClass('active');
|
||||
});
|
||||
|
||||
// 聊天窗口使用slimscroll
|
||||
$('.small-chat-box .content').slimScroll({
|
||||
height: '234px',
|
||||
railOpacity: 0.4
|
||||
});
|
||||
|
||||
// Small todo handler
|
||||
$('.check-link').click(function () {
|
||||
var button = $(this).find('i');
|
||||
var label = $(this).next('span');
|
||||
button.toggleClass('fa-check-square').toggleClass('fa-square-o');
|
||||
label.toggleClass('todo-completed');
|
||||
return false;
|
||||
});
|
||||
|
||||
//固定菜单栏
|
||||
$(function () {
|
||||
$('.sidebar-collapse').slimScroll({
|
||||
height: '100%',
|
||||
railOpacity: 0.9,
|
||||
alwaysVisible: false
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// 菜单切换
|
||||
$('.navbar-minimalize').click(function () {
|
||||
$("body").toggleClass("mini-navbar");
|
||||
SmoothlyMenu();
|
||||
});
|
||||
|
||||
|
||||
// 侧边栏高度
|
||||
function fix_height() {
|
||||
var heightWithoutNavbar = $("body > #wrapper").height() - 61;
|
||||
$(".sidebard-panel").css("min-height", heightWithoutNavbar + "px");
|
||||
}
|
||||
fix_height();
|
||||
|
||||
$(window).bind("load resize click scroll", function () {
|
||||
if (!$("body").hasClass('body-small')) {
|
||||
fix_height();
|
||||
}
|
||||
});
|
||||
|
||||
//侧边栏滚动
|
||||
$(window).scroll(function () {
|
||||
if ($(window).scrollTop() > 0 && !$('body').hasClass('fixed-nav')) {
|
||||
$('#right-sidebar').addClass('sidebar-top');
|
||||
} else {
|
||||
$('#right-sidebar').removeClass('sidebar-top');
|
||||
}
|
||||
});
|
||||
|
||||
$('.full-height-scroll').slimScroll({
|
||||
height: '100%'
|
||||
});
|
||||
|
||||
$('#side-menu>li').click(function () {
|
||||
if ($('body').hasClass('mini-navbar')) {
|
||||
NavToggle();
|
||||
}
|
||||
});
|
||||
$('#side-menu>li li a').click(function () {
|
||||
if ($(window).width() < 769) {
|
||||
NavToggle();
|
||||
}
|
||||
});
|
||||
|
||||
$('.nav-close').click(NavToggle);
|
||||
|
||||
//ios浏览器兼容性处理
|
||||
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
|
||||
$('#content-main').css('overflow-y', 'auto');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$(window).bind("load resize", function () {
|
||||
if ($(this).width() < 769) {
|
||||
$('body').addClass('mini-navbar');
|
||||
$('.navbar-static-side').fadeIn();
|
||||
}
|
||||
});
|
||||
|
||||
function NavToggle() {
|
||||
$('.navbar-minimalize').trigger('click');
|
||||
}
|
||||
|
||||
function SmoothlyMenu() {
|
||||
if (!$('body').hasClass('mini-navbar')) {
|
||||
$('#side-menu').hide();
|
||||
setTimeout(
|
||||
function () {
|
||||
$('#side-menu').fadeIn(500);
|
||||
}, 100);
|
||||
} else if ($('body').hasClass('fixed-sidebar')) {
|
||||
$('#side-menu').hide();
|
||||
setTimeout(
|
||||
function () {
|
||||
$('#side-menu').fadeIn(500);
|
||||
}, 300);
|
||||
} else {
|
||||
$('#side-menu').removeAttr('style');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//主题设置
|
||||
$(function () {
|
||||
|
||||
// 顶部菜单固定
|
||||
$('#fixednavbar').click(function () {
|
||||
if ($('#fixednavbar').is(':checked')) {
|
||||
$(".navbar-static-top").removeClass('navbar-static-top').addClass('navbar-fixed-top');
|
||||
$("body").removeClass('boxed-layout');
|
||||
$("body").addClass('fixed-nav');
|
||||
$('#boxedlayout').prop('checked', false);
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("boxedlayout", 'off');
|
||||
}
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("fixednavbar", 'on');
|
||||
}
|
||||
} else {
|
||||
$(".navbar-fixed-top").removeClass('navbar-fixed-top').addClass('navbar-static-top');
|
||||
$("body").removeClass('fixed-nav');
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("fixednavbar", 'off');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 收起左侧菜单
|
||||
$('#collapsemenu').click(function () {
|
||||
if ($('#collapsemenu').is(':checked')) {
|
||||
$("body").addClass('mini-navbar');
|
||||
SmoothlyMenu();
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("collapse_menu", 'on');
|
||||
}
|
||||
|
||||
} else {
|
||||
$("body").removeClass('mini-navbar');
|
||||
SmoothlyMenu();
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("collapse_menu", 'off');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 固定宽度
|
||||
$('#boxedlayout').click(function () {
|
||||
if ($('#boxedlayout').is(':checked')) {
|
||||
$("body").addClass('boxed-layout');
|
||||
$('#fixednavbar').prop('checked', false);
|
||||
$(".navbar-fixed-top").removeClass('navbar-fixed-top').addClass('navbar-static-top');
|
||||
$("body").removeClass('fixed-nav');
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("fixednavbar", 'off');
|
||||
}
|
||||
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("boxedlayout", 'on');
|
||||
}
|
||||
} else {
|
||||
$("body").removeClass('boxed-layout');
|
||||
|
||||
if (localStorageSupport) {
|
||||
localStorage.setItem("boxedlayout", 'off');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 默认主题
|
||||
$('.s-skin-0').click(function () {
|
||||
$("body").removeClass("skin-1");
|
||||
$("body").removeClass("skin-2");
|
||||
$("body").removeClass("skin-3");
|
||||
return false;
|
||||
});
|
||||
|
||||
// 蓝色主题
|
||||
$('.s-skin-1').click(function () {
|
||||
$("body").removeClass("skin-2");
|
||||
$("body").removeClass("skin-3");
|
||||
$("body").addClass("skin-1");
|
||||
return false;
|
||||
});
|
||||
|
||||
// 黄色主题
|
||||
$('.s-skin-3').click(function () {
|
||||
$("body").removeClass("skin-1");
|
||||
$("body").removeClass("skin-2");
|
||||
$("body").addClass("skin-3");
|
||||
return false;
|
||||
});
|
||||
|
||||
if (localStorageSupport) {
|
||||
var collapse = localStorage.getItem("collapse_menu");
|
||||
var fixednavbar = localStorage.getItem("fixednavbar");
|
||||
var boxedlayout = localStorage.getItem("boxedlayout");
|
||||
|
||||
if (collapse == 'on') {
|
||||
$('#collapsemenu').prop('checked', 'checked')
|
||||
}
|
||||
if (fixednavbar == 'on') {
|
||||
$('#fixednavbar').prop('checked', 'checked')
|
||||
}
|
||||
if (boxedlayout == 'on') {
|
||||
$('#boxedlayout').prop('checked', 'checked')
|
||||
}
|
||||
}
|
||||
|
||||
if (localStorageSupport) {
|
||||
|
||||
var collapse = localStorage.getItem("collapse_menu");
|
||||
var fixednavbar = localStorage.getItem("fixednavbar");
|
||||
var boxedlayout = localStorage.getItem("boxedlayout");
|
||||
|
||||
var body = $('body');
|
||||
|
||||
if (collapse == 'on') {
|
||||
if (!body.hasClass('body-small')) {
|
||||
body.addClass('mini-navbar');
|
||||
}
|
||||
}
|
||||
|
||||
if (fixednavbar == 'on') {
|
||||
$(".navbar-static-top").removeClass('navbar-static-top').addClass('navbar-fixed-top');
|
||||
body.addClass('fixed-nav');
|
||||
}
|
||||
|
||||
if (boxedlayout == 'on') {
|
||||
body.addClass('boxed-layout');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//判断浏览器是否支持html5本地存储
|
||||
function localStorageSupport() {
|
||||
return (('localStorage' in window) && window['localStorage'] !== null)
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
|
||||
$(function () {
|
||||
//计算元素集合的总宽度
|
||||
function calSumWidth(elements) {
|
||||
var width = 0;
|
||||
$(elements).each(function () {
|
||||
width += $(this).outerWidth(true);
|
||||
});
|
||||
return width;
|
||||
}
|
||||
//滚动到指定选项卡
|
||||
function scrollToTab(element) {
|
||||
var marginLeftVal = calSumWidth($(element).prevAll()), marginRightVal = calSumWidth($(element).nextAll());
|
||||
// 可视区域非tab宽度
|
||||
var tabOuterWidth = calSumWidth($(".content-tabs").children().not(".J_menuTabs"));
|
||||
//可视区域tab宽度
|
||||
var visibleWidth = $(".content-tabs").outerWidth(true) - tabOuterWidth;
|
||||
//实际滚动宽度
|
||||
var scrollVal = 0;
|
||||
if ($(".page-tabs-content").outerWidth() < visibleWidth) {
|
||||
scrollVal = 0;
|
||||
} else if (marginRightVal <= (visibleWidth - $(element).outerWidth(true) - $(element).next().outerWidth(true))) {
|
||||
if ((visibleWidth - $(element).next().outerWidth(true)) > marginRightVal) {
|
||||
scrollVal = marginLeftVal;
|
||||
var tabElement = element;
|
||||
while ((scrollVal - $(tabElement).outerWidth()) > ($(".page-tabs-content").outerWidth() - visibleWidth)) {
|
||||
scrollVal -= $(tabElement).prev().outerWidth();
|
||||
tabElement = $(tabElement).prev();
|
||||
}
|
||||
}
|
||||
} else if (marginLeftVal > (visibleWidth - $(element).outerWidth(true) - $(element).prev().outerWidth(true))) {
|
||||
scrollVal = marginLeftVal - $(element).prev().outerWidth(true);
|
||||
}
|
||||
$('.page-tabs-content').animate({
|
||||
marginLeft: 0 - scrollVal + 'px'
|
||||
}, "fast");
|
||||
}
|
||||
//查看左侧隐藏的选项卡
|
||||
function scrollTabLeft() {
|
||||
var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left')));
|
||||
// 可视区域非tab宽度
|
||||
var tabOuterWidth = calSumWidth($(".content-tabs").children().not(".J_menuTabs"));
|
||||
//可视区域tab宽度
|
||||
var visibleWidth = $(".content-tabs").outerWidth(true) - tabOuterWidth;
|
||||
//实际滚动宽度
|
||||
var scrollVal = 0;
|
||||
if ($(".page-tabs-content").width() < visibleWidth) {
|
||||
return false;
|
||||
} else {
|
||||
var tabElement = $(".J_menuTab:first");
|
||||
var offsetVal = 0;
|
||||
while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) {//找到离当前tab最近的元素
|
||||
offsetVal += $(tabElement).outerWidth(true);
|
||||
tabElement = $(tabElement).next();
|
||||
}
|
||||
offsetVal = 0;
|
||||
if (calSumWidth($(tabElement).prevAll()) > visibleWidth) {
|
||||
while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) {
|
||||
offsetVal += $(tabElement).outerWidth(true);
|
||||
tabElement = $(tabElement).prev();
|
||||
}
|
||||
scrollVal = calSumWidth($(tabElement).prevAll());
|
||||
}
|
||||
}
|
||||
$('.page-tabs-content').animate({
|
||||
marginLeft: 0 - scrollVal + 'px'
|
||||
}, "fast");
|
||||
}
|
||||
//查看右侧隐藏的选项卡
|
||||
function scrollTabRight() {
|
||||
var marginLeftVal = Math.abs(parseInt($('.page-tabs-content').css('margin-left')));
|
||||
// 可视区域非tab宽度
|
||||
var tabOuterWidth = calSumWidth($(".content-tabs").children().not(".J_menuTabs"));
|
||||
//可视区域tab宽度
|
||||
var visibleWidth = $(".content-tabs").outerWidth(true) - tabOuterWidth;
|
||||
//实际滚动宽度
|
||||
var scrollVal = 0;
|
||||
if ($(".page-tabs-content").width() < visibleWidth) {
|
||||
return false;
|
||||
} else {
|
||||
var tabElement = $(".J_menuTab:first");
|
||||
var offsetVal = 0;
|
||||
while ((offsetVal + $(tabElement).outerWidth(true)) <= marginLeftVal) {//找到离当前tab最近的元素
|
||||
offsetVal += $(tabElement).outerWidth(true);
|
||||
tabElement = $(tabElement).next();
|
||||
}
|
||||
offsetVal = 0;
|
||||
while ((offsetVal + $(tabElement).outerWidth(true)) < (visibleWidth) && tabElement.length > 0) {
|
||||
offsetVal += $(tabElement).outerWidth(true);
|
||||
tabElement = $(tabElement).next();
|
||||
}
|
||||
scrollVal = calSumWidth($(tabElement).prevAll());
|
||||
if (scrollVal > 0) {
|
||||
$('.page-tabs-content').animate({
|
||||
marginLeft: 0 - scrollVal + 'px'
|
||||
}, "fast");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//通过遍历给菜单项加上data-index属性
|
||||
$(".J_menuItem").each(function (index) {
|
||||
if (!$(this).attr('data-index')) {
|
||||
$(this).attr('data-index', index);
|
||||
}
|
||||
});
|
||||
|
||||
function menuItem() {
|
||||
// 获取标识数据
|
||||
var dataUrl = $(this).attr('href'),
|
||||
dataIndex = $(this).data('index'),
|
||||
menuName = $.trim($(this).text()),
|
||||
flag = true;
|
||||
if (dataUrl == undefined || $.trim(dataUrl).length == 0)return false;
|
||||
|
||||
// 选项卡菜单已存在
|
||||
$('.J_menuTab').each(function () {
|
||||
if ($(this).data('id') == dataUrl) {
|
||||
if (!$(this).hasClass('active')) {
|
||||
$(this).addClass('active').siblings('.J_menuTab').removeClass('active');
|
||||
scrollToTab(this);
|
||||
// 显示tab对应的内容区
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == dataUrl) {
|
||||
$(this).show().siblings('.J_iframe').hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
flag = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 选项卡菜单不存在
|
||||
if (flag) {
|
||||
var str = '<a href="javascript:;" class="active J_menuTab" data-id="' + dataUrl + '">' + menuName + ' <i class="fa fa-times-circle"></i></a>';
|
||||
$('.J_menuTab').removeClass('active');
|
||||
|
||||
// 添加选项卡对应的iframe
|
||||
var str1 = '<iframe class="J_iframe" name="iframe' + dataIndex + '" width="100%" height="100%" src="' + dataUrl + '" frameborder="0" data-id="' + dataUrl + '" seamless></iframe>';
|
||||
$('.J_mainContent').find('iframe.J_iframe').hide().parents('.J_mainContent').append(str1);
|
||||
|
||||
//显示loading提示
|
||||
// var loading = layer.load();
|
||||
//
|
||||
// $('.J_mainContent iframe:visible').load(function () {
|
||||
// //iframe加载完成后隐藏loading提示
|
||||
// layer.close(loading);
|
||||
// });
|
||||
// 添加选项卡
|
||||
$('.J_menuTabs .page-tabs-content').append(str);
|
||||
scrollToTab($('.J_menuTab.active'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$('.J_menuItem').on('click', menuItem);
|
||||
|
||||
// 关闭选项卡菜单
|
||||
function closeTab() {
|
||||
var closeTabId = $(this).parents('.J_menuTab').data('id');
|
||||
var currentWidth = $(this).parents('.J_menuTab').width();
|
||||
|
||||
// 当前元素处于活动状态
|
||||
if ($(this).parents('.J_menuTab').hasClass('active')) {
|
||||
|
||||
// 当前元素后面有同辈元素,使后面的一个元素处于活动状态
|
||||
if ($(this).parents('.J_menuTab').next('.J_menuTab').size()) {
|
||||
|
||||
var activeId = $(this).parents('.J_menuTab').next('.J_menuTab:eq(0)').data('id');
|
||||
$(this).parents('.J_menuTab').next('.J_menuTab:eq(0)').addClass('active');
|
||||
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == activeId) {
|
||||
$(this).show().siblings('.J_iframe').hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
var marginLeftVal = parseInt($('.page-tabs-content').css('margin-left'));
|
||||
if (marginLeftVal < 0) {
|
||||
$('.page-tabs-content').animate({
|
||||
marginLeft: (marginLeftVal + currentWidth) + 'px'
|
||||
}, "fast");
|
||||
}
|
||||
|
||||
// 移除当前选项卡
|
||||
$(this).parents('.J_menuTab').remove();
|
||||
|
||||
// 移除tab对应的内容区
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == closeTabId) {
|
||||
$(this).remove();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 当前元素后面没有同辈元素,使当前元素的上一个元素处于活动状态
|
||||
if ($(this).parents('.J_menuTab').prev('.J_menuTab').size()) {
|
||||
var activeId = $(this).parents('.J_menuTab').prev('.J_menuTab:last').data('id');
|
||||
$(this).parents('.J_menuTab').prev('.J_menuTab:last').addClass('active');
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == activeId) {
|
||||
$(this).show().siblings('.J_iframe').hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 移除当前选项卡
|
||||
$(this).parents('.J_menuTab').remove();
|
||||
|
||||
// 移除tab对应的内容区
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == closeTabId) {
|
||||
$(this).remove();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// 当前元素不处于活动状态
|
||||
else {
|
||||
// 移除当前选项卡
|
||||
$(this).parents('.J_menuTab').remove();
|
||||
|
||||
// 移除相应tab对应的内容区
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == closeTabId) {
|
||||
$(this).remove();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
scrollToTab($('.J_menuTab.active'));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$('.J_menuTabs').on('click', '.J_menuTab i', closeTab);
|
||||
|
||||
//关闭其他选项卡
|
||||
function closeOtherTabs(){
|
||||
$('.page-tabs-content').children("[data-id]").not(":first").not(".active").each(function () {
|
||||
$('.J_iframe[data-id="' + $(this).data('id') + '"]').remove();
|
||||
$(this).remove();
|
||||
});
|
||||
$('.page-tabs-content').css("margin-left", "0");
|
||||
}
|
||||
$('.J_tabCloseOther').on('click', closeOtherTabs);
|
||||
|
||||
//滚动到已激活的选项卡
|
||||
function showActiveTab(){
|
||||
scrollToTab($('.J_menuTab.active'));
|
||||
}
|
||||
$('.J_tabShowActive').on('click', showActiveTab);
|
||||
|
||||
|
||||
// 点击选项卡菜单
|
||||
function activeTab() {
|
||||
if (!$(this).hasClass('active')) {
|
||||
var currentId = $(this).data('id');
|
||||
// 显示tab对应的内容区
|
||||
$('.J_mainContent .J_iframe').each(function () {
|
||||
if ($(this).data('id') == currentId) {
|
||||
$(this).show().siblings('.J_iframe').hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$(this).addClass('active').siblings('.J_menuTab').removeClass('active');
|
||||
scrollToTab(this);
|
||||
}
|
||||
}
|
||||
|
||||
$('.J_menuTabs').on('click', '.J_menuTab', activeTab);
|
||||
|
||||
//刷新iframe
|
||||
function refreshTab() {
|
||||
var target = $('.J_iframe[data-id="' + $(this).data('id') + '"]');
|
||||
var url = target.attr('src');
|
||||
// //显示loading提示
|
||||
// var loading = layer.load();
|
||||
// target.attr('src', url).load(function () {
|
||||
// //关闭loading提示
|
||||
// layer.close(loading);
|
||||
// });
|
||||
}
|
||||
|
||||
$('.J_menuTabs').on('dblclick', '.J_menuTab', refreshTab);
|
||||
|
||||
// 左移按扭
|
||||
$('.J_tabLeft').on('click', scrollTabLeft);
|
||||
|
||||
// 右移按扭
|
||||
$('.J_tabRight').on('click', scrollTabRight);
|
||||
|
||||
// 关闭全部
|
||||
$('.J_tabCloseAll').on('click', function () {
|
||||
$('.page-tabs-content').children("[data-id]").not(":first").each(function () {
|
||||
$('.J_iframe[data-id="' + $(this).data('id') + '"]').remove();
|
||||
$(this).remove();
|
||||
});
|
||||
$('.page-tabs-content').children("[data-id]:first").each(function () {
|
||||
$('.J_iframe[data-id="' + $(this).data('id') + '"]').show();
|
||||
$(this).addClass("active");
|
||||
});
|
||||
$('.page-tabs-content').css("margin-left", "0");
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* metismenu - v1.1.3
|
||||
* Easy menu jQuery plugin for Twitter Bootstrap 3
|
||||
* https://github.com/onokumus/metisMenu
|
||||
*
|
||||
* Made by Osman Nuri Okumus
|
||||
* Under MIT License
|
||||
*/
|
||||
;(function($, window, document, undefined) {
|
||||
|
||||
var pluginName = "metisMenu",
|
||||
defaults = {
|
||||
toggle: true,
|
||||
doubleTapToGo: false
|
||||
};
|
||||
|
||||
function Plugin(element, options) {
|
||||
this.element = $(element);
|
||||
this.settings = $.extend({}, defaults, options);
|
||||
this._defaults = defaults;
|
||||
this._name = pluginName;
|
||||
this.init();
|
||||
}
|
||||
|
||||
Plugin.prototype = {
|
||||
init: function() {
|
||||
|
||||
var $this = this.element,
|
||||
$toggle = this.settings.toggle,
|
||||
obj = this;
|
||||
|
||||
if (this.isIE() <= 9) {
|
||||
$this.find("li.active").has("ul").children("ul").collapse("show");
|
||||
$this.find("li").not(".active").has("ul").children("ul").collapse("hide");
|
||||
} else {
|
||||
$this.find("li.active").has("ul").children("ul").addClass("collapse in");
|
||||
$this.find("li").not(".active").has("ul").children("ul").addClass("collapse");
|
||||
}
|
||||
|
||||
//add the "doubleTapToGo" class to active items if needed
|
||||
if (obj.settings.doubleTapToGo) {
|
||||
$this.find("li.active").has("ul").children("a").addClass("doubleTapToGo");
|
||||
}
|
||||
|
||||
$this.find("li").has("ul").children("a").on("click" + "." + pluginName, function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
//Do we need to enable the double tap
|
||||
if (obj.settings.doubleTapToGo) {
|
||||
|
||||
//if we hit a second time on the link and the href is valid, navigate to that url
|
||||
if (obj.doubleTapToGo($(this)) && $(this).attr("href") !== "#" && $(this).attr("href") !== "") {
|
||||
e.stopPropagation();
|
||||
document.location = $(this).attr("href");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$(this).parent("li").toggleClass("active").children("ul").collapse("toggle");
|
||||
|
||||
if ($toggle) {
|
||||
$(this).parent("li").siblings().removeClass("active").children("ul.in").collapse("hide");
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
isIE: function() { //https://gist.github.com/padolsey/527683
|
||||
var undef,
|
||||
v = 3,
|
||||
div = document.createElement("div"),
|
||||
all = div.getElementsByTagName("i");
|
||||
|
||||
while (
|
||||
div.innerHTML = "<!--[if gt IE " + (++v) + "]><i></i><![endif]-->",
|
||||
all[0]
|
||||
) {
|
||||
return v > 4 ? v : undef;
|
||||
}
|
||||
},
|
||||
|
||||
//Enable the link on the second click.
|
||||
doubleTapToGo: function(elem) {
|
||||
var $this = this.element;
|
||||
|
||||
//if the class "doubleTapToGo" exists, remove it and return
|
||||
if (elem.hasClass("doubleTapToGo")) {
|
||||
elem.removeClass("doubleTapToGo");
|
||||
return true;
|
||||
}
|
||||
|
||||
//does not exists, add a new class and return false
|
||||
if (elem.parent().children("ul").length) {
|
||||
//first remove all other class
|
||||
$this.find(".doubleTapToGo").removeClass("doubleTapToGo");
|
||||
//add the class on the current element
|
||||
elem.addClass("doubleTapToGo");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
this.element.off("." + pluginName);
|
||||
this.element.removeData(pluginName);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn[pluginName] = function(options) {
|
||||
this.each(function () {
|
||||
var el = $(this);
|
||||
if (el.data(pluginName)) {
|
||||
el.data(pluginName).remove();
|
||||
}
|
||||
el.data(pluginName, new Plugin(this, options));
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
})(jQuery, window, document);
|
File diff suppressed because one or more lines are too long
15
sparchetype/src/main/resources/static/js/plugins/slimscroll/jquery.slimscroll.min.js
vendored
Normal file
15
sparchetype/src/main/resources/static/js/plugins/slimscroll/jquery.slimscroll.min.js
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
|
||||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||||
*
|
||||
* Version: 1.3.0
|
||||
*
|
||||
*/
|
||||
(function(f){jQuery.fn.extend({slimScroll:function(h){var a=f.extend({width:"auto",height:"250px",size:"4px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:0.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},h);this.each(function(){function r(d){if(s){d=d||
|
||||
window.event;var c=0;d.wheelDelta&&(c=-d.wheelDelta/120);d.detail&&(c=d.detail/3);f(d.target||d.srcTarget||d.srcElement).closest("."+a.wrapperClass).is(b.parent())&&m(c,!0);d.preventDefault&&!k&&d.preventDefault();k||(d.returnValue=!1)}}function m(d,f,h){k=!1;var e=d,g=b.outerHeight()-c.outerHeight();f&&(e=parseInt(c.css("top"))+d*parseInt(a.wheelStep)/100*c.outerHeight(),e=Math.min(Math.max(e,0),g),e=0<d?Math.ceil(e):Math.floor(e),c.css({top:e+"px"}));l=parseInt(c.css("top"))/(b.outerHeight()-c.outerHeight());
|
||||
e=l*(b[0].scrollHeight-b.outerHeight());h&&(e=d,d=e/b[0].scrollHeight*b.outerHeight(),d=Math.min(Math.max(d,0),g),c.css({top:d+"px"}));b.scrollTop(e);b.trigger("slimscrolling",~~e);v();p()}function C(){window.addEventListener?(this.addEventListener("DOMMouseScroll",r,!1),this.addEventListener("mousewheel",r,!1),this.addEventListener("MozMousePixelScroll",r,!1)):document.attachEvent("onmousewheel",r)}function w(){u=Math.max(b.outerHeight()/b[0].scrollHeight*b.outerHeight(),D);c.css({height:u+"px"});
|
||||
var a=u==b.outerHeight()?"none":"block";c.css({display:a})}function v(){w();clearTimeout(A);l==~~l?(k=a.allowPageScroll,B!=l&&b.trigger("slimscroll",0==~~l?"top":"bottom")):k=!1;B=l;u>=b.outerHeight()?k=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&g.stop(!0,!0).fadeIn("fast"))}function p(){a.alwaysVisible||(A=setTimeout(function(){a.disableFadeOut&&s||(x||y)||(c.fadeOut("slow"),g.fadeOut("slow"))},1E3))}var s,x,y,A,z,u,l,B,D=30,k=!1,b=f(this);if(b.parent().hasClass(a.wrapperClass)){var n=b.scrollTop(),
|
||||
c=b.parent().find("."+a.barClass),g=b.parent().find("."+a.railClass);w();if(f.isPlainObject(h)){if("height"in h&&"auto"==h.height){b.parent().css("height","auto");b.css("height","auto");var q=b.parent().parent().height();b.parent().css("height",q);b.css("height",q)}if("scrollTo"in h)n=parseInt(a.scrollTo);else if("scrollBy"in h)n+=parseInt(a.scrollBy);else if("destroy"in h){c.remove();g.remove();b.unwrap();return}m(n,!1,!0)}}else{a.height="auto"==a.height?b.parent().height():a.height;n=f("<div></div>").addClass(a.wrapperClass).css({position:"relative",width:a.width,height:a.height});b.css({width:a.width,height:a.height});var g=f("<div></div>").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.railBorderRadius,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=f("<div></div>").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible?
|
||||
"block":"none","border-radius":a.borderRadius,BorderRadius:a.borderRadius,MozBorderRadius:a.borderRadius,WebkitBorderRadius:a.borderRadius,zIndex:99}),q="right"==a.position?{right:a.distance}:{left:a.distance};g.css(q);c.css(q);b.wrap(n);b.parent().append(c);b.parent().append(g);a.railDraggable&&c.bind("mousedown",function(a){var b=f(document);y=!0;t=parseFloat(c.css("top"));pageY=a.pageY;b.bind("mousemove.slimscroll",function(a){currTop=t+a.pageY-pageY;c.css("top",currTop);m(0,c.position().top,!1)});
|
||||
b.bind("mouseup.slimscroll",function(a){y=!1;p();b.unbind(".slimscroll")});return!1}).bind("selectstart.slimscroll",function(a){a.stopPropagation();a.preventDefault();return!1});g.hover(function(){v()},function(){p()});c.hover(function(){x=!0},function(){x=!1});b.hover(function(){s=!0;v();p()},function(){s=!1;p()});b.bind("touchstart",function(a,b){a.originalEvent.touches.length&&(z=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){k||b.originalEvent.preventDefault();b.originalEvent.touches.length&&
|
||||
(m((z-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0),z=b.originalEvent.touches[0].pageY)});w();"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),m(0,!0)):"top"!==a.start&&(m(f(a.start).position().top,null,!0),a.alwaysVisible||c.hide());C()}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery);
|
|
@ -0,0 +1,2 @@
|
|||
!function(e){e(["jquery"],function(e){return function(){function t(e,t,n){return f({type:O.error,iconClass:g().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=g()),v=e("#"+t.containerId),v.length?v:(n&&(v=c(t)),v)}function i(e,t,n){return f({type:O.info,iconClass:g().iconClasses.info,message:e,optionsOverride:n,title:t})}function o(e){w=e}function s(e,t,n){return f({type:O.success,iconClass:g().iconClasses.success,message:e,optionsOverride:n,title:t})}function a(e,t,n){return f({type:O.warning,iconClass:g().iconClasses.warning,message:e,optionsOverride:n,title:t})}function r(e){var t=g();v||n(t),l(e,t)||u(t)}function d(t){var i=g();return v||n(i),t&&0===e(":focus",t).length?void h(t):void(v.children().length&&v.remove())}function u(t){for(var n=v.children(),i=n.length-1;i>=0;i--)l(e(n[i]),t)}function l(t,n){return t&&0===e(":focus",t).length?(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){h(t)}}),!0):!1}function c(t){return v=e("<div/>").attr("id",t.containerId).addClass(t.positionClass).attr("aria-live","polite").attr("role","alert"),v.appendTo(e(t.target)),v}function p(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",target:"body",closeHtml:'<button type="button">×</button>',newestOnTop:!0,preventDuplicates:!1,progressBar:!1}}function m(e){w&&w(e)}function f(t){function i(t){return!e(":focus",l).length||t?(clearTimeout(O.intervalId),l[r.hideMethod]({duration:r.hideDuration,easing:r.hideEasing,complete:function(){h(l),r.onHidden&&"hidden"!==b.state&&r.onHidden(),b.state="hidden",b.endTime=new Date,m(b)}})):void 0}function o(){(r.timeOut>0||r.extendedTimeOut>0)&&(u=setTimeout(i,r.extendedTimeOut),O.maxHideTime=parseFloat(r.extendedTimeOut),O.hideEta=(new Date).getTime()+O.maxHideTime)}function s(){clearTimeout(u),O.hideEta=0,l.stop(!0,!0)[r.showMethod]({duration:r.showDuration,easing:r.showEasing})}function a(){var e=(O.hideEta-(new Date).getTime())/O.maxHideTime*100;f.width(e+"%")}var r=g(),d=t.iconClass||r.iconClass;if("undefined"!=typeof t.optionsOverride&&(r=e.extend(r,t.optionsOverride),d=t.optionsOverride.iconClass||d),r.preventDuplicates){if(t.message===C)return;C=t.message}T++,v=n(r,!0);var u=null,l=e("<div/>"),c=e("<div/>"),p=e("<div/>"),f=e("<div/>"),w=e(r.closeHtml),O={intervalId:null,hideEta:null,maxHideTime:null},b={toastId:T,state:"visible",startTime:new Date,options:r,map:t};return t.iconClass&&l.addClass(r.toastClass).addClass(d),t.title&&(c.append(t.title).addClass(r.titleClass),l.append(c)),t.message&&(p.append(t.message).addClass(r.messageClass),l.append(p)),r.closeButton&&(w.addClass("toast-close-button").attr("role","button"),l.prepend(w)),r.progressBar&&(f.addClass("toast-progress"),l.prepend(f)),l.hide(),r.newestOnTop?v.prepend(l):v.append(l),l[r.showMethod]({duration:r.showDuration,easing:r.showEasing,complete:r.onShown}),r.timeOut>0&&(u=setTimeout(i,r.timeOut),O.maxHideTime=parseFloat(r.timeOut),O.hideEta=(new Date).getTime()+O.maxHideTime,r.progressBar&&(O.intervalId=setInterval(a,10))),l.hover(s,o),!r.onclick&&r.tapToDismiss&&l.click(i),r.closeButton&&w&&w.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),i(!0)}),r.onclick&&l.click(function(){r.onclick(),i()}),m(b),r.debug&&console&&console.log(b),l}function g(){return e.extend({},p(),b.options)}function h(e){v||(v=n()),e.is(":visible")||(e.remove(),e=null,0===v.children().length&&(v.remove(),C=void 0))}var v,w,C,T=0,O={error:"error",info:"info",success:"success",warning:"warning"},b={clear:r,remove:d,error:t,getContainer:n,info:i,options:{},subscribe:o,success:s,version:"2.1.0",warning:a};return b}()})}("function"==typeof define&&define.amd?define:function(e,t){"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):window.toastr=t(window.jQuery)});
|
||||
//# sourceMappingURL=/toastr.js.map
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,47 @@
|
|||
<head th:fragment="header">
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title></title>
|
||||
<meta name="keywords" content="">
|
||||
<meta name="description" content="">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link href="css/bootstrap.min.css?v=3.3.6"
|
||||
th:href="@{/css/bootstrap.min.css?v=3.3.6}" rel="stylesheet">
|
||||
<link href="/css/font-awesome.css?v=4.4.0"
|
||||
th:href="@{/css/font-awesome.css?v=4.4.0}" rel="stylesheet">
|
||||
<link href="/css/plugins/bootstrap-table/bootstrap-table.min.css"
|
||||
th:href="@{/css/plugins/bootstrap-table/bootstrap-table.min.css}"
|
||||
rel="stylesheet">
|
||||
<link href="/css/plugins/jsTree/style.min.css" rel="stylesheet">
|
||||
<link href="/css/plugins/jqTreeGrid/jquery.treegrid.css"
|
||||
rel="stylesheet">
|
||||
<!--summernote css -->
|
||||
<link href="/css/plugins/summernote/summernote-0.8.8.css"
|
||||
rel="stylesheet">
|
||||
<link href="css/animate.css" th:href="@{/css/animate.css}"
|
||||
rel="stylesheet">
|
||||
<link href="/css/plugins/chosen/chosen.css" rel="stylesheet">
|
||||
<link href="/css/style.css?v=4.1.0" th:href="@{/css/style.css?v=4.1.0}"
|
||||
rel="stylesheet">
|
||||
</head>
|
||||
<div th:fragment="footer">
|
||||
|
||||
<script src="/js/jquery.min.js?v=2.1.4"></script>
|
||||
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
|
||||
<script src="/js/plugins/bootstrap-table/bootstrap-table.min.js"></script>
|
||||
<script src="/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js"></script>
|
||||
<script
|
||||
src="/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
|
||||
<script src="/js/plugins/validate/jquery.validate.min.js"></script>
|
||||
<script src="/js/plugins/validate/messages_zh.min.js"></script>
|
||||
<script src="/js/plugins/jsTree/jstree.min.js"></script>
|
||||
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.min.js"></script>
|
||||
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.extension.js"></script>
|
||||
<script src="/js/plugins/jqTreeGrid/jquery.treegrid.bootstrap3.js"></script>
|
||||
<script src="/js/plugins/chosen/chosen.jquery.js"></script>
|
||||
<script src="/js/plugins/layer/layer.js"></script>
|
||||
<script src="/js/content.js?v=1.0.0"></script>
|
||||
<!--summernote-->
|
||||
<script src="/js/plugins/summernote/summernote.js"></script>
|
||||
<script src="/js/plugins/summernote/summernote-zh-CN.min.js"></script>
|
||||
<script src="/js/ajax-util.js"></script>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="renderer" content="webkit">
|
||||
<title>面向学习型的开源框架,简洁高效,减少过渡封装,展现技术本质</title>
|
||||
<meta name="keywords" content="面向学习型的开源框架,简洁高效,杜绝过渡封装,展现技术本质本质">
|
||||
<meta name="description" content="面向学习型的开源框架,简洁高效,杜绝过渡封装,展现技术本质本质">
|
||||
<!--[if lt IE 9]>
|
||||
<meta http-equiv="refresh" content="0;ie.html"/>
|
||||
<![endif]-->
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link href="/css/bootstrap.min.css?v=3.3.6" rel="stylesheet">
|
||||
<link href="/css/font-awesome.min.css?v=4.4.0" rel="stylesheet">
|
||||
<link href="/css/plugins/toastr/toastr.min.css" rel="stylesheet">
|
||||
<link href="/css/animate.css" rel="stylesheet">
|
||||
<link href="/css/style.css?v=4.1.0" rel="stylesheet">
|
||||
</head>
|
||||
<body class="fixed-sidebar full-height-layout gray-bg"
|
||||
style="overflow: hidden">
|
||||
<div id="wrapper">
|
||||
<!--左侧导航开始-->
|
||||
<nav class="navbar-default navbar-static-side" role="navigation">
|
||||
<div class="nav-close">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
</div>
|
||||
<div class="sidebar-collapse">
|
||||
<ul class="nav" id="side-menu">
|
||||
<li class="nav-header">
|
||||
<div>
|
||||
<span><img alt="image" class="img-circle" height="60" width="60" th:src="${picUrl}"/></span>
|
||||
<h3 class="" style="color: #ffffff">
|
||||
</i>BootDo后台管理系统
|
||||
</h3>
|
||||
</div>
|
||||
<div class="dropdown profile-element hidden">
|
||||
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="clear">
|
||||
<span class="block m-t-xs"><strong class="font-bold"
|
||||
th:text="${username}">admin</strong></span>
|
||||
<span class="text-muted text-xs block">超级管理员<b class="caret"></b></span>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu animated fadeInRight m-t-xs">
|
||||
<li><a @click="personal" href="#">修改头像</a>
|
||||
</li>
|
||||
<li><a @click="personal" href="#">个人资料</a>
|
||||
</li>
|
||||
<li><a @click="personal" href="#">密码修改</a>
|
||||
</li>
|
||||
<li><a @click="personal" href="#">信箱</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="/logout">安全退出</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="logo-element">BootDo</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#"> <i class="fa fa-home"></i> <span
|
||||
class="nav-label">主页</span> <span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li><a id="index001" class="J_menuItem" href="index_v1.html"
|
||||
data-index="0" th:href="@{/main}">了解BootDo</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li th:each="menu : ${menus}"><a href="#"> <i
|
||||
class="fa fa fa-bar-chart-o" th:class="${menu.attributes.icon}"></i>
|
||||
<span class="nav-label" th:text="${menu.text}">基础信息</span> <span
|
||||
class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li th:each="cmenu : ${menu.children}"><a class="J_menuItem" href="graph_echarts.html"
|
||||
th:text="${cmenu.text}"
|
||||
th:href="${cmenu.attributes.url}">系统管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<!--左侧导航结束-->
|
||||
<!--右侧部分开始-->
|
||||
<div id="page-wrapper" class="gray-bg dashbard-1">
|
||||
<div class="row border-bottom">
|
||||
<nav class="navbar navbar-static-top" role="navigation"
|
||||
style="margin-bottom: 0">
|
||||
<div class="navbar-header">
|
||||
|
||||
<a class="navbar-minimalize minimalize-styl-2 btn btn-default "
|
||||
href="#" title="收起菜单"><i class="fa fa-bars"></i> </a>
|
||||
<form role="search" class="navbar-form-custom"
|
||||
method="post" action="">
|
||||
<div class="form-group">
|
||||
<input type="text" placeholder="请输入您需要查找的内容 …"
|
||||
class="form-control" name="top-search" id="top-search">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<ul class="nav navbar-top-links navbar-right">
|
||||
<li class="hidden-xs"><a href="/blog" target="_Blank"
|
||||
class=""><i class="fa fa-rss-square"></i>博客</a></li>
|
||||
<li class="dropdown"><a class="dropdown-toggle count-info"
|
||||
data-toggle="dropdown" href="#"> <i class="fa fa-envelope"></i>
|
||||
<span class="label label-warning">{{total}}</span>通知
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-messages">
|
||||
<li v-for="row in rows" class="m-t-xs">
|
||||
<div class="dropdown-messages-box">
|
||||
<a class="pull-left"> <i
|
||||
class="fa fa-server"></i>
|
||||
</a>
|
||||
<div class="media-body">
|
||||
<small class="pull-right">{{row.before}}</small>
|
||||
<strong>{{row.sender}}</strong>
|
||||
{{row.title}} <br>
|
||||
<small class="text-muted">{{row.updateDate}}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="text-center link-block">
|
||||
<a class="J_menuItem" href="/oa/notify/selfNotify"> <i
|
||||
class="fa fa-envelope"></i> <strong> 查看所有消息</strong>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="hidden-xs"><a @click="personal" href="#"><i class="fa fa-id-card"></i> 个人</a></li>
|
||||
<li class="dropdown hidden-xs"><a
|
||||
class="right-sidebar-toggle" aria-expanded="false"> <i
|
||||
class="fa fa-tasks"></i> 主题
|
||||
</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="row content-tabs">
|
||||
<button class="roll-nav roll-left J_tabLeft">
|
||||
<i class="fa fa-backward"></i>
|
||||
</button>
|
||||
<nav class="page-tabs J_menuTabs">
|
||||
<div class="page-tabs-content">
|
||||
<a href="javascript:;" class="active J_menuTab"
|
||||
data-id="index_v1.html">首页</a>
|
||||
</div>
|
||||
</nav>
|
||||
<button class="roll-nav roll-right J_tabRight">
|
||||
<i class="fa fa-forward"></i>
|
||||
</button>
|
||||
<div class="btn-group roll-nav roll-right">
|
||||
<button class="dropdown J_tabClose" data-toggle="dropdown">
|
||||
关闭操作<span class="caret"></span>
|
||||
</button>
|
||||
<ul role="menu" class="dropdown-menu dropdown-menu-right">
|
||||
<li class="J_tabShowActive"><a>定位当前选项卡</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="J_tabCloseAll"><a>关闭全部选项卡</a></li>
|
||||
<li class="J_tabCloseOther"><a>关闭其他选项卡</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="/logout" class="roll-nav roll-right J_tabExit"><i
|
||||
class="fa fa fa-sign-out"></i> 退出</a>
|
||||
</div>
|
||||
<div class="row J_mainContent" id="content-main">
|
||||
<iframe class="J_iframe" name="iframe0" width="100%" height="100%"
|
||||
src="" th:src="@{/main}" frameborder="0" data-id="index.html" seamless></iframe>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="pull-right">BootDo面向学习型的开源框架</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--右侧部分结束-->
|
||||
<!--右侧边栏开始-->
|
||||
<div id="right-sidebar">
|
||||
<div class="sidebar-container">
|
||||
<ul class="nav nav-tabs navs-3">
|
||||
|
||||
<li class="active"><a data-toggle="tab" href="#tab-1"> <i
|
||||
class="fa fa-gear"></i> 主题
|
||||
</a></li>
|
||||
<li class=""><a data-toggle="tab" href="#tab-2"> 通知 </a></li>
|
||||
<li><a data-toggle="tab" href="#tab-3"> 项目进度 </a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div id="tab-1" class="tab-pane active">
|
||||
<div class="sidebar-title">
|
||||
<h3>
|
||||
<i class="fa fa-comments-o"></i> 主题设置
|
||||
</h3>
|
||||
<small><i class="fa fa-tim"></i>
|
||||
你可以从这里选择和预览主题的布局和样式,这些设置会被保存在本地,下次打开的时候会直接应用这些设置。
|
||||
</small>
|
||||
</div>
|
||||
<div class="skin-setttings">
|
||||
<div class="title">主题设置</div>
|
||||
<div class="setings-item">
|
||||
<span>收起左侧菜单</span>
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" name="collapsemenu"
|
||||
class="onoffswitch-checkbox" id="collapsemenu"> <label
|
||||
class="onoffswitch-label" for="collapsemenu"> <span
|
||||
class="onoffswitch-inner"></span> <span
|
||||
class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setings-item">
|
||||
<span>固定顶部</span>
|
||||
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" name="fixednavbar"
|
||||
class="onoffswitch-checkbox" id="fixednavbar"> <label
|
||||
class="onoffswitch-label" for="fixednavbar"> <span
|
||||
class="onoffswitch-inner"></span> <span
|
||||
class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setings-item">
|
||||
<span> 固定宽度 </span>
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" name="boxedlayout"
|
||||
class="onoffswitch-checkbox" id="boxedlayout"> <label
|
||||
class="onoffswitch-label" for="boxedlayout"> <span
|
||||
class="onoffswitch-inner"></span> <span
|
||||
class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">皮肤选择</div>
|
||||
<div class="setings-item default-skin nb">
|
||||
<span class="skin-name "> <a href="#" class="s-skin-0">
|
||||
默认皮肤 </a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="setings-item blue-skin nb">
|
||||
<span class="skin-name "> <a href="#" class="s-skin-1">
|
||||
蓝色主题 </a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="setings-item yellow-skin nb">
|
||||
<span class="skin-name "> <a href="#" class="s-skin-3">
|
||||
黄色/紫色主题 </a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-2" class="tab-pane">
|
||||
|
||||
<div class="sidebar-title">
|
||||
<h3>
|
||||
<i class="fa fa-comments-o"></i> 最新通知
|
||||
</h3>
|
||||
<small><i class="fa fa-tim"></i> 您当前有10条未读信息</small>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-3" class="tab-pane">
|
||||
|
||||
<div class="sidebar-title">
|
||||
<h3>
|
||||
<i class="fa fa-cube"></i> 最新任务
|
||||
</h3>
|
||||
<small><i class="fa fa-tim"></i> 您当前有14个任务,10个已完成</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 全局js -->
|
||||
<script src="/js/jquery.min.js?v=2.1.4"></script>
|
||||
<script src="/js/bootstrap.min.js?v=3.3.6"></script>
|
||||
<script src="/js/plugins/metisMenu/jquery.metisMenu.js"></script>
|
||||
<script src="/js/plugins/slimscroll/jquery.slimscroll.min.js"></script>
|
||||
<script src="/js/plugins/layer/layer.min.js"></script>
|
||||
<!-- 自定义js -->
|
||||
<script src="/js/app.js?v=4.1.0"></script>
|
||||
<script type="text/javascript" src="/js/contabs.js"></script>
|
||||
<!-- 第三方插件 -->
|
||||
<script src="/js/plugins/pace/pace.min.js"></script>
|
||||
<!-- vue -->
|
||||
<script type="text/javascript"
|
||||
src="/js/vue.min.js">
|
||||
|
||||
</script>
|
||||
<script src="/js/appjs/oa/webSocket/sockjs.min.js"></script>
|
||||
<script src="/js/appjs/oa/webSocket/stomp.min.js"></script>
|
||||
<!-- Toastr script -->
|
||||
<script src="/js/plugins/toastr/toastr.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
var stompClient = null;
|
||||
$(function () {
|
||||
connect();
|
||||
});
|
||||
|
||||
function connect() {
|
||||
var sock = new SockJS("/endpointChat");
|
||||
var stomp = Stomp.over(sock);
|
||||
stomp.connect('guest', 'guest', function (frame) {
|
||||
|
||||
/**
订阅了/user/queue/notifications 发送的消息,这里雨在控制器的 convertAndSendToUser 定义的地址保持一致,
|
||||
* 这里多用了一个/user,并且这个user 是必须的,使用user 才会发送消息到指定的用户。
|
||||
* */
|
||||
stomp.subscribe("/user/queue/notifications", handleNotification);
|
||||
stomp.subscribe('/topic/getResponse', function (response) { //订阅/topic/getResponse 目标发送的消息。这个是在控制器的@SendTo中定义的。
|
||||
toastr.options = {
|
||||
"closeButton": true,
|
||||
"debug": false,
|
||||
"progressBar": true,
|
||||
"positionClass": "toast-bottom-right",
|
||||
"onclick": null,
|
||||
"showDuration": "400",
|
||||
"hideDuration": "1000",
|
||||
"timeOut": "7000",
|
||||
"extendedTimeOut": "1000",
|
||||
"showEasing": "swing",
|
||||
"hideEasing": "linear",
|
||||
"showMethod": "fadeIn",
|
||||
"hideMethod": "fadeOut"
|
||||
}
|
||||
toastr.info(JSON.parse(response.body).responseMessage);
|
||||
});
|
||||
});
|
||||
|
||||
function handleNotification(message) {
|
||||
wrapper.notify();
|
||||
toastr.info(message.body);
|
||||
}
|
||||
}
|
||||
|
||||
var wrapper = new Vue({
|
||||
el: '#wrapper',
|
||||
data: {
|
||||
total: '',
|
||||
rows: '',
|
||||
},
|
||||
methods: {
|
||||
notify: function () {
|
||||
$.getJSON('/oa/notify/message', function (r) {
|
||||
wrapper.total = r.total;
|
||||
wrapper.rows = r.rows;
|
||||
});
|
||||
},
|
||||
personal: function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '个人设置',
|
||||
maxmin: true,
|
||||
shadeClose: false,
|
||||
area: ['800px', '600px'],
|
||||
content: '/sys/user/personal'
|
||||
});
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
this.notify()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>欢迎页</title>
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">了解BootDo</div>
|
||||
<div style="padding: 10px 0 20px 10px;">
|
||||
<h3> 项目介绍</h3>
|
||||
<ul>
|
||||
<li>面向学习型的开源框架,简洁高效,减少过渡封装,展现技术本质</li>
|
||||
<li>Springboot作为基础框架,使用mybatis作为持久层框架</li>
|
||||
<li>使用官方推荐的thymeleaf做为模板引擎,shiro作为安全框架,主流技术,“一网打尽”</li>
|
||||
<li>极简配置,一键前后台代码生成</li>
|
||||
</ul>
|
||||
|
||||
<h3> 获取源码</h3>
|
||||
<ul>
|
||||
<li>Github地址:<a href="https://github.com/lcg0124/bootdo.git"
|
||||
th:href="@{https://github.com/lcg0124/bootdo.git}" target="_blank">https://github.com/lcg0124/bootdo.git</a>
|
||||
</li>
|
||||
<li>Oschina地址:<a href="https://gitee.com/lcg0124/bootdo.git" target="_blank">https://gitee.com/lcg0124/bootdo.git</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3> 官方QQ群</h3>
|
||||
<ul>
|
||||
<li>点击链接加入群聊【BootDo交流群】:<a href="https://jq.qq.com/?_wv=1027&k=5EYXfiZ">669039323</a></li>
|
||||
<li>点击链接加入群聊【BootDo交流二群】:<a href="https://jq.qq.com/?_wv=1027&k=5M659N4">614726589</a></li>
|
||||
<li>点击链接加入群聊【BootDo交流三群】:<a href="https://jq.qq.com/?_wv=1027&k=5tE3A9O">600801035</a></li>
|
||||
<li>点击链接加入群聊【CloudDo交流群】:<a href="https://jq.qq.com/?_wv=1027&k=5Zk12Xl">719741533</a></li>
|
||||
</ul>
|
||||
|
||||
<button class="btn" onclick="openPage('http://bootdo.com','bootdo.com')">访问bootdo官网(新打开tab页事例)</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/openTab.js"></script>
|
||||
</html>
|
Loading…
Reference in New Issue