Commit a1af464c by zwb

招聘会演示平台搭建与简历导入

parent 613f3bfd
Showing with 2142 additions and 0 deletions
package com.bkty.system.api.model;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 角色
*
* @author Lion Li
*/
@Data
@NoArgsConstructor
public class RoleDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 角色ID
*/
private Long roleId;
/**
* 角色名称
*/
private String roleName;
/**
* 角色权限
*/
private String roleKey;
/**
* 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
*/
private String dataScope;
}
package com.bkty.form;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.domain.model.LoginBody;
/**
* 短信登录对象
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SmsLoginBody extends LoginBody {
/**
* 手机号
*/
@NotBlank(message = "{user.phonenumber.not.blank}")
private String phonenumber;
/**
* 短信code
*/
@NotBlank(message = "{sms.code.not.blank}")
private String smsCode;
}
package com.bkty.form;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.domain.model.LoginBody;
/**
* 三方登录对象
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SocialLoginBody extends LoginBody {
/**
* 第三方登录平台
*/
@NotBlank(message = "{social.source.not.blank}")
private String source;
/**
* 第三方登录code
*/
@NotBlank(message = "{social.code.not.blank}")
private String socialCode;
/**
* 第三方登录socialState
*/
@NotBlank(message = "{social.state.not.blank}")
private String socialState;
}
package org.dromara.common.core.config;
import lombok.Data;
@Data
public class Sort extends Page {
/** 排序参数:DESC降序;ASC-升序 */
private String sortRule;
/** 排序字段 */
private String sortField;
}
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.*;
/**
* @author jiangxiaoge
* @description 学校层次枚举
* @data 2025/1/21
**/
@Getter
@AllArgsConstructor
public enum SchoolLevelEnum {
/**
* 正常
*/
S_985(0, "985工程"),
/**
* 停用
*/
S_211(1, "211工程"),
/**
* 删除
*/
S_ONE(2, "一本"),
S_TWO(3, "二本"),
S_JUNGLE(4, "大专");
private final int code;
private final String info;
/**
* 根据 code 获得对应的枚举类
* @param code 指定的 code
* @return 对应的枚举类,若没有,则返回null
*/
public static SchoolLevelEnum getEnumsByCode(int code){
for (SchoolLevelEnum sendEnums : EnumSet.allOf(SchoolLevelEnum.class)) {
if(sendEnums.code == code){
return sendEnums;
}
}
return null;
}
/**
*
* 将枚举值转换成列表,方便下拉框使用
* @return
* @author Herbert
*/
public static List<Map<String, Object>> getSchoolLevel(){
Map<String, Object> map = null;
List<Map<String, Object>> lstResult = new ArrayList<>(10);
for (SchoolLevelEnum typeEnum : EnumSet.allOf(SchoolLevelEnum.class)) {
map = new HashMap<>(16);
map.put("key", typeEnum.getCode());
map.put("value", typeEnum.getInfo());
lstResult.add(map);
}
return lstResult;
}
}
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author jiangxiaoge
* @description 学校购买类型
* @data 2025/1/21
**/
@Getter
@AllArgsConstructor
public enum SchoolShoppingEnum {
PAY(0, "付费购买"),
NO_PAY(1, "免费赠送");
private final int code;
private final String name;
}
package org.dromara.common.core.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* 业务异常
*
* @author ruoyi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class ServiceException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*/
private String detailMessage;
public ServiceException(String message) {
this.message = message;
}
public ServiceException(String message, Integer code) {
this.message = message;
this.code = code;
}
public String getDetailMessage() {
return detailMessage;
}
@Override
public String getMessage() {
return message;
}
public Integer getCode() {
return code;
}
public ServiceException setMessage(String message) {
this.message = message;
return this;
}
public ServiceException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
}
package org.dromara.common.core.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* sse 特制异常
*
* @author LionLi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class SseException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*/
private String detailMessage;
public SseException(String message) {
this.message = message;
}
public SseException(String message, Integer code) {
this.message = message;
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public SseException setMessage(String message) {
this.message = message;
return this;
}
public SseException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
}
package org.dromara.common.core.utils;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.UserLoginInfo;
import org.dromara.common.core.exception.JxgException;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 安全工具类
*
* @author jiangxiaoge
*/
@UtilityClass
@Slf4j
public class SecurityUtils {
// /**
// * 获取Authentication
// */
// public Authentication getAuthentication() {
// return SecurityContextHolder.getContext().getAuthentication();
// }
//
// /**
// * 获取用户
// *
// * @param authentication
// * @return PanguUser
// * <p>
// * 获取当前用户的全部信息 EnablePanguResourceServer true
// * 获取当前用户的用户名 EnablePanguResourceServer false
// */
// public PanguUser getUser(Authentication authentication) {
// Object principal = authentication.getPrincipal();
// if (principal instanceof PanguUser) {
// return (PanguUser) principal;
// }
// return new PanguNullUser();
// }
//
// /**
// * 获取用户
// */
// public PanguUser getUser() {
// Authentication authentication = getAuthentication();
// if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
// return new PanguNullUser();
// }
// return getUser(authentication);
// }
public UserLoginInfo getUser(String token){
if (StringUtils.isBlank(token)){
return null;
}
if (token.startsWith("Bearer ")) {
token = token.substring(7);
}
try {
return JwtUtil.verifyJwt(token, UserLoginInfo.class);
} catch (Exception e) {
throw new JxgException("token验证失败", 401);
}
}
/**
* 获取用户
*/
public UserLoginInfo getUser() {
if (WebUtils.getRequest() == null){
String token = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest()
.getHeader(HttpHeaders.AUTHORIZATION);
return getUser(token);
}
String tokenString = WebUtils.getRequest().getHeader(HttpHeaders.AUTHORIZATION);
return getUser(tokenString);
}
/**
* 获取当前用户名
*
* @return String
*/
/*public String getUsername() {
String userStr = WebUtils.getRequest().getHeader(SecurityConstants.HEADER_PANGU_USER);
if (StrUtil.isEmpty(userStr)) {
return null;
}
try {
TokenUser user = new ObjectMapper().readValue(userStr, TokenUser.class);
return user.getUsername();
} catch (JsonProcessingException e) {
throw new PanguException(e);
}
}*/
}
package org.dromara.common.core.utils;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* 客户端工具类
*
* @author ruoyi
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ServletUtils extends JakartaServletUtil {
/**
* 获取String参数
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name) {
return Convert.toBool(getRequest().getParameter(name));
}
/**
* 获取Boolean参数
*/
public static Boolean getParameterToBool(String name, Boolean defaultValue) {
return Convert.toBool(getRequest().getParameter(name), defaultValue);
}
/**
* 获得所有请求参数
*
* @param request 请求对象{@link ServletRequest}
* @return Map
*/
public static Map<String, String[]> getParams(ServletRequest request) {
final Map<String, String[]> map = request.getParameterMap();
return Collections.unmodifiableMap(map);
}
/**
* 获得所有请求参数
*
* @param request 请求对象{@link ServletRequest}
* @return Map
*/
public static Map<String, String> getParamMap(ServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) {
params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR));
}
return params;
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
try {
return getRequestAttributes().getRequest();
} catch (Exception e) {
return null;
}
}
/**
* 获取response
*/
public static HttpServletResponse getResponse() {
try {
return getRequestAttributes().getResponse();
} catch (Exception e) {
return null;
}
}
/**
* 获取session
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes() {
try {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
} catch (Exception e) {
return null;
}
}
public static String getHeader(HttpServletRequest request, String name) {
String value = request.getHeader(name);
if (StringUtils.isEmpty(value)) {
return StringUtils.EMPTY;
}
return urlDecode(value);
}
public static Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedCaseInsensitiveMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
*/
public static void renderString(HttpServletResponse response, String string) {
try {
response.setStatus(HttpStatus.HTTP_OK);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 是否是Ajax异步请求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
return true;
}
String ajax = request.getParameter("__ajax");
return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml");
}
public static String getClientIP() {
return getClientIP(getRequest());
}
/**
* 内容编码
*
* @param str 内容
* @return 编码后的内容
*/
public static String urlEncode(String str) {
return URLEncoder.encode(str, StandardCharsets.UTF_8);
}
/**
* 内容解码
*
* @param str 内容
* @return 解码后的内容
*/
public static String urlDecode(String str) {
return URLDecoder.decode(str, StandardCharsets.UTF_8);
}
}
package org.dromara.common.core.utils;
public class SnowFlakeUtil {
//下面两个每个5位,加起来就是10位的工作机器id
private long workerId; //工作id
private long datacenterId; //数据id
//12位的序列号
private long sequence;
public SnowFlakeUtil(long workerId, long datacenterId, long sequence){
// sanity check for workerId
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
}
System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",
timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
this.workerId = workerId;
this.datacenterId = datacenterId;
this.sequence = sequence;
}
//初始时间戳
private long twepoch = 1397072021154L;
//长度为5位
private long workerIdBits = 5L;
private long datacenterIdBits = 5L;
//最大值
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
//序列号id长度
private long sequenceBits = 12L;
//序列号最大值
private long sequenceMask = -1L ^ (-1L << sequenceBits);
//工作id需要左移的位数,12位
private long workerIdShift = sequenceBits;
//数据id需要左移位数 12+5=17位
private long datacenterIdShift = sequenceBits + workerIdBits;
//时间戳需要左移位数 12+5+5=22位
private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
//上次时间戳,初始值为负数
private long lastTimestamp = -1L;
public long getWorkerId(){
return workerId;
}
public long getDatacenterId(){
return datacenterId;
}
public long getTimestamp(){
return System.currentTimeMillis();
}
//下一个ID生成算法
public synchronized long nextId() {
long timestamp = timeGen();
//获取当前时间戳如果小于上次时间戳,则表示时间戳获取出现异常
if (timestamp < lastTimestamp) {
System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp);
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
}
//获取当前时间戳如果等于上次时间戳(同一毫秒内),则在序列号加一;否则序列号赋值为0,从0开始。
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
//将上次时间戳值刷新
lastTimestamp = timestamp;
/**
* 返回结果:
* (timestamp - twepoch) << timestampLeftShift) 表示将时间戳减去初始时间戳,再左移相应位数
* (datacenterId << datacenterIdShift) 表示将数据id左移相应位数
* (workerId << workerIdShift) 表示将工作id左移相应位数
* | 是按位或运算符,例如:x | y,只有当x,y都为0的时候结果才为0,其它情况结果都为1。
* 因为个部分只有相应位上的值有意义,其它位上都是0,所以将各部分的值进行 | 运算就能得到最终拼接好的id
*/
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
//获取时间戳,并与上次时间戳比较
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
//获取系统时间戳
private long timeGen(){
return System.currentTimeMillis();
}
//单例模式
private static final SnowFlakeUtil instance = new SnowFlakeUtil(1,1,1);
public static long newId(){
return instance.nextId();
}
public static String newIdString(){
return String.valueOf(instance.nextId());
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(SnowFlakeUtil.newIdString());
}
}
}
package org.dromara.common.core.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* Spring 工具类
*
* @author jiangxiaoge
*/
@Slf4j
@Service
@Lazy(false)
public class SpringContextHolder implements BeanFactoryPostProcessor, ApplicationContextAware, DisposableBean {
private static ConfigurableListableBeanFactory beanFactory;
private static ApplicationContext applicationContext = null;
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* BeanFactoryPostProcessor, 注入Context到静态变量中.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
SpringContextHolder.beanFactory = factory;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringContextHolder.applicationContext = applicationContext;
}
public static ListableBeanFactory getBeanFactory() {
return null == beanFactory ? applicationContext : beanFactory;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) getBeanFactory().getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, Map<Bean名称,实现类></>
*/
public static <T> Map<String, T> getBeansOfType(Class<T> type) {
return getBeanFactory().getBeansOfType(type);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return getBeanFactory().getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
if (log.isDebugEnabled()) {
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
}
applicationContext = null;
}
/**
* 发布事件
* @param event
*/
public static void publishEvent(ApplicationEvent event) {
if (applicationContext == null) {
return;
}
applicationContext.publishEvent(event);
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() {
SpringContextHolder.clearHolder();
}
/**
* 获取当前profile
*/
public static String getActiveProfile() {
if (applicationContext == null || applicationContext.getEnvironment().getActiveProfiles().length <= 0) {
return null;
}
return applicationContext.getEnvironment().getActiveProfiles()[0];
}
/**
* 获取当前profile
*/
public static boolean isDevProfile() {
return "dev".equals(getActiveProfile());
}
}
\ No newline at end of file
package org.dromara.common.core.utils;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.autoconfigure.thread.Threading;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* spring工具类
*
* @author Lion Li
*/
@Component
public final class SpringUtils extends SpringUtil {
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*/
public static boolean containsBean(String name) {
return getBeanFactory().containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().isSingleton(name);
}
/**
* @return Class 注册对象的类型
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return getBeanFactory().getAliases(name);
}
/**
* 获取aop代理对象
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) getBean(invoker.getClass());
}
/**
* 获取spring上下文
*/
public static ApplicationContext context() {
return getApplicationContext();
}
public static boolean isVirtual() {
return Threading.VIRTUAL.isActive(getBean(Environment.class));
}
}
package org.dromara.common.core.utils.sql;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.StringUtils;
/**
* sql操作工具类
*
* @author ruoyi
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SqlUtil {
/**
* 定义常用的 sql关键字
*/
public static String SQL_REGEX = "and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
*/
public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 检查字符,防止注入绕过
*/
public static String escapeOrderBySql(String value) {
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
throw new IllegalArgumentException("参数不符合规范,不能进行查询");
}
return value;
}
/**
* 验证 order by 语法是否符合规范
*/
public static boolean isValidOrderBySql(String value) {
return value.matches(SQL_PATTERN);
}
/**
* SQL关键字检查
*/
public static void filterKeyword(String value) {
if (StringUtils.isEmpty(value)) {
return;
}
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
for (String sqlKeyword : sqlKeywords) {
if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
throw new IllegalArgumentException("参数存在SQL注入风险");
}
}
}
}
package org.dromara.common.doc.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.doc.config.properties.SpringDocProperties;
import org.dromara.common.doc.handler.OpenApiHandler;
import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.OpenApiCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.JavadocProvider;
import org.springdoc.core.service.OpenAPIService;
import org.springdoc.core.service.SecurityService;
import org.springdoc.core.utils.PropertyResolverUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import java.util.*;
/**
* Swagger 文档配置
*
* @author Lion Li
*/
@RequiredArgsConstructor
@AutoConfiguration(before = SpringDocConfiguration.class)
@EnableConfigurationProperties(SpringDocProperties.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
public class SpringDocAutoConfiguration {
private final ServerProperties serverProperties;
@Value("${spring.application.name}")
private String appName;
@Bean
@ConditionalOnMissingBean(OpenAPI.class)
public OpenAPI openApi(SpringDocProperties properties) {
OpenAPI openApi = new OpenAPI();
// 文档基本信息
SpringDocProperties.InfoProperties infoProperties = properties.getInfo();
Info info = convertInfo(infoProperties);
openApi.info(info);
// 扩展文档信息
openApi.externalDocs(properties.getExternalDocs());
openApi.tags(properties.getTags());
openApi.paths(properties.getPaths());
openApi.components(properties.getComponents());
Set<String> keySet = properties.getComponents().getSecuritySchemes().keySet();
List<SecurityRequirement> list = new ArrayList<>();
SecurityRequirement securityRequirement = new SecurityRequirement();
keySet.forEach(securityRequirement::addList);
list.add(securityRequirement);
openApi.security(list);
return openApi;
}
private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
Info info = new Info();
info.setTitle(infoProperties.getTitle());
info.setDescription(infoProperties.getDescription());
info.setContact(infoProperties.getContact());
info.setLicense(infoProperties.getLicense());
info.setVersion(infoProperties.getVersion());
return info;
}
/**
* 自定义 openapi 处理器
*/
@Bean
public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI,
SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) {
return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider);
}
/**
* 对已经生成好的 OpenApi 进行自定义操作
*/
@Bean
public OpenApiCustomizer openApiCustomizer() {
// 拼接服务路径
String appPath = "/" + StringUtils.substring(appName, appName.indexOf("-") + 1);
String contextPath = serverProperties.getServlet().getContextPath();
String finalContextPath;
if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) {
finalContextPath = appPath;
} else {
finalContextPath = appPath + contextPath;
}
// 对所有路径增加前置上下文路径
return openApi -> {
Paths oldPaths = openApi.getPaths();
if (oldPaths instanceof PlusPaths) {
return;
}
PlusPaths newPaths = new PlusPaths();
oldPaths.forEach((k, v) -> newPaths.addPathItem(finalContextPath + k, v));
openApi.setPaths(newPaths);
};
}
}
package org.dromara.common.doc.config.properties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.tags.Tag;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import java.util.List;
/**
* swagger 配置属性
*
* @author Lion Li
*/
@Data
@ConfigurationProperties(prefix = "springdoc")
public class SpringDocProperties {
/**
* 文档基本信息
*/
@NestedConfigurationProperty
private InfoProperties info = new InfoProperties();
/**
* 扩展文档地址
*/
@NestedConfigurationProperty
private ExternalDocumentation externalDocs;
/**
* 标签
*/
private List<Tag> tags = null;
/**
* 路径
*/
@NestedConfigurationProperty
private Paths paths = null;
/**
* 组件
*/
@NestedConfigurationProperty
private Components components = null;
/**
* <p>
* 文档的基础属性信息
* </p>
*
* @see io.swagger.v3.oas.models.info.Info
*
* 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来
*/
@Data
public static class InfoProperties {
/**
* 标题
*/
private String title = null;
/**
* 描述
*/
private String description = null;
/**
* 联系人信息
*/
@NestedConfigurationProperty
private Contact contact = null;
/**
* 许可证
*/
@NestedConfigurationProperty
private License license = null;
/**
* 版本
*/
private String version = null;
}
}
package org.dromara.common.encrypt.core.encryptor;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.core.EncryptContext;
import org.dromara.common.encrypt.enumd.AlgorithmType;
import org.dromara.common.encrypt.enumd.EncodeType;
import org.dromara.common.encrypt.utils.EncryptUtils;
/**
* RSA算法实现
*
* @author 老马
* @version 4.6.0
*/
public class RsaEncryptor extends AbstractEncryptor {
private final EncryptContext context;
public RsaEncryptor(EncryptContext context) {
super(context);
String privateKey = context.getPrivateKey();
String publicKey = context.getPublicKey();
if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。");
}
this.context = context;
}
/**
* 获得当前算法
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.RSA;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
*/
@Override
public String encrypt(String value, EncodeType encodeType) {
if (encodeType == EncodeType.HEX) {
return EncryptUtils.encryptByRsaHex(value, context.getPublicKey());
} else {
return EncryptUtils.encryptByRsa(value, context.getPublicKey());
}
}
/**
* 解密
*
* @param value 待加密字符串
*/
@Override
public String decrypt(String value) {
return EncryptUtils.decryptByRsa(value, context.getPrivateKey());
}
}
package org.dromara.common.encrypt.core.encryptor;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.core.EncryptContext;
import org.dromara.common.encrypt.enumd.AlgorithmType;
import org.dromara.common.encrypt.enumd.EncodeType;
import org.dromara.common.encrypt.utils.EncryptUtils;
/**
* sm2算法实现
*
* @author 老马
* @version 4.6.0
*/
public class Sm2Encryptor extends AbstractEncryptor {
private final EncryptContext context;
public Sm2Encryptor(EncryptContext context) {
super(context);
String privateKey = context.getPrivateKey();
String publicKey = context.getPublicKey();
if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。");
}
this.context = context;
}
/**
* 获得当前算法
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.SM2;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
*/
@Override
public String encrypt(String value, EncodeType encodeType) {
if (encodeType == EncodeType.HEX) {
return EncryptUtils.encryptBySm2Hex(value, context.getPublicKey());
} else {
return EncryptUtils.encryptBySm2(value, context.getPublicKey());
}
}
/**
* 解密
*
* @param value 待加密字符串
*/
@Override
public String decrypt(String value) {
return EncryptUtils.decryptBySm2(value, context.getPrivateKey());
}
}
package org.dromara.common.encrypt.core.encryptor;
import org.dromara.common.encrypt.core.EncryptContext;
import org.dromara.common.encrypt.enumd.AlgorithmType;
import org.dromara.common.encrypt.enumd.EncodeType;
import org.dromara.common.encrypt.utils.EncryptUtils;
/**
* sm4算法实现
*
* @author 老马
* @version 4.6.0
*/
public class Sm4Encryptor extends AbstractEncryptor {
private final EncryptContext context;
public Sm4Encryptor(EncryptContext context) {
super(context);
this.context = context;
}
/**
* 获得当前算法
*/
@Override
public AlgorithmType algorithm() {
return AlgorithmType.SM4;
}
/**
* 加密
*
* @param value 待加密字符串
* @param encodeType 加密后的编码格式
*/
@Override
public String encrypt(String value, EncodeType encodeType) {
if (encodeType == EncodeType.HEX) {
return EncryptUtils.encryptBySm4Hex(value, context.getPassword());
} else {
return EncryptUtils.encryptBySm4(value, context.getPassword());
}
}
/**
* 解密
*
* @param value 待加密字符串
*/
@Override
public String decrypt(String value) {
return EncryptUtils.decryptBySm4(value, context.getPassword());
}
}
# p6spy 性能分析插件配置文件
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# SQL语句打印时间格式
databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
# 是否过滤 Log
filter=true
# 过滤 Log 时所排除的 sql 关键字,以逗号分隔
exclude=
package org.dromara.common.satoken.config;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
import org.dromara.common.satoken.core.service.SaPermissionImpl;
import org.dromara.common.satoken.handler.SaTokenExceptionHandler;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
/**
* Sa-Token 配置
*
* @author Lion Li
*/
@AutoConfiguration
@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
public class SaTokenConfiguration {
@Bean
public StpLogic getStpLogicJwt() {
return new StpLogicJwtForSimple();
}
/**
* 权限接口实现(使用bean注入方便用户替换)
*/
@Bean
public StpInterface stpInterface() {
return new SaPermissionImpl();
}
/**
* 自定义dao层存储
*/
@Bean
public SaTokenDao saTokenDao() {
return new PlusSaTokenDao();
}
/**
* 异常处理器
*/
@Bean
public SaTokenExceptionHandler saTokenExceptionHandler() {
return new SaTokenExceptionHandler();
}
}
package org.dromara.common.satoken.core.service;
import cn.dev33.satoken.stp.StpInterface;
import com.bkty.system.api.model.LoginUser;
import org.dromara.common.core.enums.UserType;
import org.dromara.common.satoken.utils.LoginHelper;
import java.util.ArrayList;
import java.util.List;
/**
* sa-token 权限管理实现类
*
* @author Lion Li
*/
public class SaPermissionImpl implements StpInterface {
/**
* 获取菜单权限列表
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser();
UserType userType = UserType.getUserType(loginUser.getUserType());
if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getMenuPermission());
} else if (userType == UserType.APP_USER) {
// 其他端 自行根据业务编写
}
return new ArrayList<>();
}
/**
* 获取角色权限列表
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser();
UserType userType = UserType.getUserType(loginUser.getUserType());
if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getRolePermission());
} else if (userType == UserType.APP_USER) {
// 其他端 自行根据业务编写
}
return new ArrayList<>();
}
}
package org.dromara.common.satoken.handler;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* SaToken异常处理器
*
* @author Lion Li
*/
@Slf4j
@RestControllerAdvice
public class SaTokenExceptionHandler {
/**
* 权限码异常
*/
@ExceptionHandler(NotPermissionException.class)
public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权");
}
/**
* 角色权限异常
*/
@ExceptionHandler(NotRoleException.class)
public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage());
return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权");
}
/**
* 认证失败
*/
@ExceptionHandler(NotLoginException.class)
public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源");
}
}
package org.dromara.common.security.config;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.same.SaSameUtil;
import cn.dev33.satoken.util.SaResult;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 权限安全配置
*
* @author Lion Li
*/
@AutoConfiguration
public class SecurityConfiguration implements WebMvcConfigurer {
/**
* 注册sa-token的拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册路由拦截器,自定义验证规则
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
/**
* 校验是否从网关转发
*/
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/actuator", "/actuator/**")
.setAuth(obj -> {
if (SaManager.getConfig().getCheckSameToken()) {
SaSameUtil.checkCurrentRequestToken();
}
})
.setError(e -> SaResult.error("认证失败,无法访问系统资源-gateway不能跳过").setCode(HttpStatus.UNAUTHORIZED));
}
/**
* 对 actuator 健康检查接口 做账号密码鉴权
*/
@Bean
public SaServletFilter actuatorFilter() {
String username = SpringUtils.getProperty("spring.cloud.nacos.discovery.metadata.username");
String password = SpringUtils.getProperty("spring.cloud.nacos.discovery.metadata.userpassword");
return new SaServletFilter()
.addInclude("/actuator", "/actuator/**")
.setAuth(obj -> {
SaHttpBasicUtil.check(username + ":" + password);
})
.setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED));
}
}
package org.dromara.common.sensitive.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.dromara.common.sensitive.core.SensitiveStrategy;
import org.dromara.common.sensitive.handler.SensitiveHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据脱敏注解
*
* @author zhujie
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveHandler.class)
public @interface Sensitive {
SensitiveStrategy strategy();
String roleKey() default "";
String perms() default "";
}
package org.dromara.common.sensitive.core;
/**
* 脱敏服务
* 默认管理员不过滤
* 需自行根据业务重写实现
*
* @author Lion Li
* @version 3.6.0
*/
public interface SensitiveService {
/**
* 是否脱敏
*/
boolean isSensitive(String roleKey, String perms);
}
package org.dromara.common.sensitive.core;
import cn.hutool.core.util.DesensitizedUtil;
import lombok.AllArgsConstructor;
import java.util.function.Function;
/**
* 脱敏策略
*
* @author Yjoioooo
* @version 3.6.0
*/
@AllArgsConstructor
public enum SensitiveStrategy {
/**
* 身份证脱敏
*/
ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)),
/**
* 手机号脱敏
*/
PHONE(DesensitizedUtil::mobilePhone),
/**
* 地址脱敏
*/
ADDRESS(s -> DesensitizedUtil.address(s, 8)),
/**
* 邮箱脱敏
*/
EMAIL(DesensitizedUtil::email),
/**
* 银行卡
*/
BANK_CARD(DesensitizedUtil::bankCard),
/**
* 中文名
*/
CHINESE_NAME(DesensitizedUtil::chineseName),
/**
* 固定电话
*/
FIXED_PHONE(DesensitizedUtil::fixedPhone),
/**
* 用户ID
*/
USER_ID(s -> String.valueOf(DesensitizedUtil.userId())),
/**
* 密码
*/
PASSWORD(DesensitizedUtil::password),
/**
* ipv4
*/
IPV4(DesensitizedUtil::ipv4),
/**
* ipv6
*/
IPV6(DesensitizedUtil::ipv6),
/**
* 中国大陆车牌,包含普通车辆、新能源车辆
*/
CAR_LICENSE(DesensitizedUtil::carLicense),
/**
* 只显示第一个字符
*/
FIRST_MASK(DesensitizedUtil::firstMask),
/**
* 清空为null
*/
CLEAR(s -> DesensitizedUtil.clear()),
/**
* 清空为""
*/
CLEAR_TO_NULL(s -> DesensitizedUtil.clearToNull());
//可自行添加其他脱敏策略
private final Function<String, String> desensitizer;
public Function<String, String> desensitizer() {
return desensitizer;
}
}
package org.dromara.common.sensitive.handler;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveService;
import org.dromara.common.sensitive.core.SensitiveStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import java.io.IOException;
import java.util.Objects;
/**
* 数据脱敏json序列化工具
*
* @author Yjoioooo
*/
@Slf4j
public class SensitiveHandler extends JsonSerializer<String> implements ContextualSerializer {
private SensitiveStrategy strategy;
private String roleKey;
private String perms;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
try {
SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class);
if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive(roleKey, perms)) {
gen.writeString(strategy.desensitizer().apply(value));
} else {
gen.writeString(value);
}
} catch (BeansException e) {
log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage());
gen.writeString(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
Sensitive annotation = property.getAnnotation(Sensitive.class);
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
this.strategy = annotation.strategy();
this.roleKey = annotation.roleKey();
this.perms = annotation.perms();
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
}
...@@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor; ...@@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.annotation.RepeatSubmit; import org.dromara.common.core.annotation.RepeatSubmit;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.JxgException;
import org.dromara.common.core.exception.WarnException; import org.dromara.common.core.exception.WarnException;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
...@@ -57,6 +58,20 @@ public class NewEditionResumeController { ...@@ -57,6 +58,20 @@ public class NewEditionResumeController {
} }
/** /**
* 查询简历模块数据
* @param dto
* @return
*/
@PostMapping("/queryModelData/{modelName}")
public R<Map<String, Object>> queryModelData(@PathVariable("modelName") String modelName, @RequestBody ResumeMakeDto dto){
if (null == dto.getResumeId()){
throw new JxgException("简历id不能为空");
}
Map<String, Object> resuleMap = this.newEditionResumeService.queryModelData(modelName, dto);
return new R<>(resuleMap);
}
/**
* 修改简历各个模块信息 * 修改简历各个模块信息
* @return * @return
*/ */
......
package com.bkty.system.domain.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 路由配置信息
*
* @author Lion Li
*/
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class RouterVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 路由名字
*/
private String name;
/**
* 路由地址
*/
private String path;
/**
* 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现
*/
private boolean hidden;
/**
* 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
*/
private String redirect;
/**
* 组件地址
*/
private String component;
/**
* 路由参数:如 {"id": 1, "name": "ry"}
*/
private String query;
/**
* 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
*/
private Boolean alwaysShow;
/**
* 其他元素
*/
private MetaVo meta;
/**
* 子路由
*/
private List<RouterVo> children;
}
...@@ -33,6 +33,12 @@ public interface NewEditionResumeService { ...@@ -33,6 +33,12 @@ public interface NewEditionResumeService {
*/ */
CompletableFuture<ResumeVo> queryNewEditionResumeId(String resumeId); CompletableFuture<ResumeVo> queryNewEditionResumeId(String resumeId);
/**
* 查询简历模块数据
* @param dto
*/
Map<String, Object> queryModelData(String modelName, ResumeMakeDto dto);
/** /**
* 修改简历各个模块信息 * 修改简历各个模块信息
......
...@@ -579,6 +579,26 @@ public class NewEditionResumeServiceImpl implements NewEditionResumeService { ...@@ -579,6 +579,26 @@ public class NewEditionResumeServiceImpl implements NewEditionResumeService {
redisTemplate.opsForValue().set(CacheConstants.REDIS_USER_RESUME_RECOMMEND_KEY.formatted(resumeId), JSON.toJSONString(vo)); redisTemplate.opsForValue().set(CacheConstants.REDIS_USER_RESUME_RECOMMEND_KEY.formatted(resumeId), JSON.toJSONString(vo));
return CompletableFuture.completedFuture(vo); return CompletableFuture.completedFuture(vo);
} }
@Override
public Map<String, Object> queryModelData(String modelName, ResumeMakeDto dto) {
Map<String, Object> dataMap = new HashMap<>();
switch (modelName) {
case "base" -> dataMap.put("data", newEditionResumeUtil.queryBaseInfo(dto));
case "edus" -> dataMap.put("data", newEditionResumeUtil.queryEduInfo(dto));
case "workExps" -> dataMap.put("data", newEditionResumeUtil.queryExtraInfo(dto));
case "projects" -> dataMap.put("data", newEditionResumeUtil.queryProjectInfo(dto));
case "skill" -> dataMap.put("data", newEditionResumeUtil.queryExtra(dto, ResumeEnum.ResumeModel.SKILL.getCode()));
case "advantage" -> dataMap.put("data", newEditionResumeUtil.queryExtra(dto, ResumeEnum.ResumeModel.ADVANTAGE.getCode()));
case "awards" -> dataMap.put("data", newEditionResumeUtil.queryExtra(dto, ResumeEnum.ResumeModel.AWARDS.getCode()));
case "hobbles" -> dataMap.put("data", newEditionResumeUtil.queryExtra(dto, ResumeEnum.ResumeModel.HOBBLES.getCode()));
case "clubs" -> dataMap.put("data", newEditionResumeUtil.queryClubInfo(dto));
case "internships" -> dataMap.put("data", newEditionResumeUtil.queryInternshipExp(dto));
case "custom" -> dataMap.put("data", newEditionResumeUtil.queryCustom(dto));
}
return dataMap;
}
@Override @Override
public Object updateModule(String modelName, ResumeMakeDto resumeMakeDto) throws Exception { public Object updateModule(String modelName, ResumeMakeDto resumeMakeDto) throws Exception {
UserLoginInfo user = new UserLoginInfo(); UserLoginInfo user = new UserLoginInfo();
......
package com.alibaba.nacos.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 权限安全配置
*
* @author Lion Li
*/
@Configuration
public class SecurityConfig {
@Value("${spring.boot.admin.client.username}")
private String username;
@Value("${spring.boot.admin.client.password}")
private String password;
@Bean
public FilterRegistrationBean<ActuatorAuthFilter> actuatorFilterRegistrationBean() {
FilterRegistrationBean<ActuatorAuthFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new ActuatorAuthFilter(username, password));
registrationBean.addUrlPatterns("/actuator", "/actuator/**");
return registrationBean;
}
}
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.console.controller;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.console.paramcheck.ConsoleDefaultHttpParamExtractor;
import com.alibaba.nacos.core.paramcheck.ExtractorManager;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.module.ModuleState;
import com.alibaba.nacos.sys.module.ModuleStateHolder;
import com.alibaba.nacos.sys.utils.DiskUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.common.utils.StringUtils.*;
/**
* Server state controller.
*
* @author xingxuechao on:2019/2/27 11:17 AM
*/
@RestController
@RequestMapping("/v1/console/server")
@ExtractorManager.Extractor(httpExtractor = ConsoleDefaultHttpParamExtractor.class)
public class ServerStateController {
private static final String ANNOUNCEMENT_FILE = "announcement.conf";
private static final String GUIDE_FILE = "console-guide.conf";
/**
* Get server state of current server.
*
* @return state json.
*/
@GetMapping("/state")
public ResponseEntity<Map<String, String>> serverState() {
Map<String, String> serverState = new HashMap<>(4);
for (ModuleState each : ModuleStateHolder.getInstance().getAllModuleStates()) {
each.getStates().forEach((s, o) -> serverState.put(s, null == o ? null : o.toString()));
}
return ResponseEntity.ok().body(serverState);
}
@GetMapping("/announcement")
public RestResult<String> getAnnouncement(
@RequestParam(required = false, name = "language", defaultValue = "zh-CN") String language) {
String file = ANNOUNCEMENT_FILE.substring(0, ANNOUNCEMENT_FILE.length() - 5) + "_" + language + ".conf";
if (file.contains(TOP_PATH) || file.contains(FOLDER_SEPARATOR) || file.contains(WINDOWS_FOLDER_SEPARATOR)) {
throw new IllegalArgumentException("Invalid filename");
}
File announcementFile = new File(EnvUtil.getConfPath(), file);
String announcement = null;
if (announcementFile.exists() && announcementFile.isFile()) {
announcement = DiskUtils.readFile(announcementFile);
}
return RestResultUtils.success(announcement);
}
@GetMapping("/guide")
public RestResult<String> getConsoleUiGuide() {
File guideFile = new File(EnvUtil.getConfPath(), GUIDE_FILE);
String guideInformation = null;
if (guideFile.exists() && guideFile.isFile()) {
guideInformation = DiskUtils.readFile(guideFile);
}
return RestResultUtils.success(guideInformation);
}
}
/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
* Released under the MIT license
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/src/ruby",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={comments:{lineComment:"#",blockComment:["=begin","=end"]},brackets:[["(",")"],["{","}"],["[","]"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t.language={tokenPostfix:".ruby",keywords:["__LINE__","__ENCODING__","__FILE__","BEGIN","END","alias","and","begin","break","case","class","def","defined?","do","else","elsif","end","ensure","for","false","if","in","module","next","nil","not","or","redo","rescue","retry","return","self","super","then","true","undef","unless","until","when","while","yield"],keywordops:["::","..","...","?",":","=>"],builtins:["require","public","private","include","extend","attr_reader","protected","private_class_method","protected_class_method","new"],declarations:["module","class","def","case","do","begin","for","if","while","until","unless"],linedecls:["def","case","do","begin","for","if","while","until","unless"],operators:["^","&","|","<=>","==","===","!~","=~",">",">=","<","<=","<<",">>","+","-","*","/","%","**","~","+@","-@","[]","[]=","`","+=","-=","*=","**=","/=","^=","%=","<<=",">>=","&=","&&=","||=","|="],brackets:[{open:"(",close:")",token:"delimiter.parenthesis"},{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"}],symbols:/[=><!~?:&|+\-*\/\^%\.]+/,escape:/(?:[abefnrstv\\"'\n\r]|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4})/,escapes:/\\(?:C\-(@escape|.)|c(@escape|.)|@escape)/,decpart:/\d(_?\d)*/,decimal:/0|@decpart/,delim:/[^a-zA-Z0-9\s\n\r]/,heredelim:/(?:\w+|'[^']*'|"[^"]*"|`[^`]*`)/,regexpctl:/[(){}\[\]\$\^|\-*+?\.]/,regexpesc:/\\(?:[AzZbBdDfnrstvwWn0\\\/]|@regexpctl|c[A-Z]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})?/,tokenizer:{root:[[/^(\s*)([a-z_]\w*[!?=]?)/,["white",{cases:{"for|until|while":{token:"keyword.$2",next:"@dodecl.$2"},"@declarations":{token:"keyword.$2",next:"@root.$2"},end:{token:"keyword.$S2",next:"@pop"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}]],[/[a-z_]\w*[!?=]?/,{cases:{"if|unless|while|until":{token:"keyword.$0x",next:"@modifier.$0x"},for:{token:"keyword.$2",next:"@dodecl.$2"},"@linedecls":{token:"keyword.$0",next:"@root.$0"},end:{token:"keyword.$S2",next:"@pop"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}],[/[A-Z][\w]*[!?=]?/,"constructor.identifier"],[/\$[\w]*/,"global.constant"],[/@[\w]*/,"namespace.instance.identifier"],[/@@[\w]*/,"namespace.class.identifier"],[/<<-(@heredelim).*/,{token:"string.heredoc.delimiter",next:"@heredoc.$1"}],[/[ \t\r\n]+<<(@heredelim).*/,{token:"string.heredoc.delimiter",next:"@heredoc.$1"}],[/^<<(@heredelim).*/,{token:"string.heredoc.delimiter",next:"@heredoc.$1"}],{include:"@whitespace"},[/"/,{token:"string.d.delim",next:'@dstring.d."'}],[/'/,{token:"string.sq.delim",next:"@sstring.sq"}],[/%([rsqxwW]|Q?)/,{token:"@rematch",next:"pstring"}],[/`/,{token:"string.x.delim",next:"@dstring.x.`"}],[/:(\w|[$@])\w*[!?=]?/,"string.s"],[/:"/,{token:"string.s.delim",next:'@dstring.s."'}],[/:'/,{token:"string.s.delim",next:"@sstring.s"}],[/\/(?=(\\\/|[^\/\n])+\/)/,{token:"regexp.delim",next:"@regexp"}],[/[{}()\[\]]/,"@brackets"],[/@symbols/,{cases:{"@keywordops":"keyword","@operators":"operator","@default":""}}],[/[;,]/,"delimiter"],[/0[xX][0-9a-fA-F](_?[0-9a-fA-F])*/,"number.hex"],[/0[_oO][0-7](_?[0-7])*/,"number.octal"],[/0[bB][01](_?[01])*/,"number.binary"],[/0[dD]@decpart/,"number"],[/@decimal((\.@decpart)?([eE][\-+]?@decpart)?)/,{cases:{$1:"number.float","@default":"number"}}]],dodecl:[[/^/,{token:"",switchTo:"@root.$S2"}],[/[a-z_]\w*[!?=]?/,{cases:{end:{token:"keyword.$S2",next:"@pop"},do:{token:"keyword",switchTo:"@root.$S2"},"@linedecls":{token:"@rematch",switchTo:"@root.$S2"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}],{include:"@root"}],modifier:[[/^/,"","@pop"],[/[a-z_]\w*[!?=]?/,{cases:{end:{token:"keyword.$S2",next:"@pop"},"then|else|elsif|do":{token:"keyword",switchTo:"@root.$S2"},"@linedecls":{token:"@rematch",switchTo:"@root.$S2"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}],{include:"@root"}],sstring:[[/[^\\']+/,"string.$S2"],[/\\\\|\\'|\\$/,"string.$S2.escape"],[/\\./,"string.$S2.invalid"],[/'/,{token:"string.$S2.delim",next:"@pop"}]],dstring:[[/[^\\`"#]+/,"string.$S2"],[/#/,"string.$S2.escape","@interpolated"],[/\\$/,"string.$S2.escape"],[/@escapes/,"string.$S2.escape"],[/\\./,"string.$S2.escape.invalid"],[/[`"]/,{cases:{"$#==$S3":{token:"string.$S2.delim",next:"@pop"},"@default":"string.$S2"}}]],heredoc:[[/^(\s*)(@heredelim)$/,{cases:{"$2==$S2":["string.heredoc",{token:"string.heredoc.delimiter",next:"@pop"}],"@default":["string.heredoc","string.heredoc"]}}],[/.*/,"string.heredoc"]],interpolated:[[/\$\w*/,"global.constant","@pop"],[/@\w*/,"namespace.class.identifier","@pop"],[/@@\w*/,"namespace.instance.identifier","@pop"],[/[{]/,{token:"string.escape.curly",switchTo:"@interpolated_compound"}],["","","@pop"]],interpolated_compound:[[/[}]/,{token:"string.escape.curly",next:"@pop"}],{include:"@root"}],pregexp:[{include:"@whitespace"},[/[^\(\{\[\\]/,{cases:{"$#==$S3":{token:"regexp.delim",next:"@pop"},"$#==$S2":{token:"regexp.delim",next:"@push"},"~[)}\\]]":"@brackets.regexp.escape.control","~@regexpctl":"regexp.escape.control","@default":"regexp"}}],{include:"@regexcontrol"}],regexp:[{include:"@regexcontrol"},[/[^\\\/]/,"regexp"],["/[ixmp]*",{token:"regexp.delim"},"@pop"]],regexcontrol:[[/(\{)(\d+(?:,\d*)?)(\})/,["@brackets.regexp.escape.control","regexp.escape.control","@brackets.regexp.escape.control"]],[/(\[)(\^?)/,["@brackets.regexp.escape.control",{token:"regexp.escape.control",next:"@regexrange"}]],[/(\()(\?[:=!])/,["@brackets.regexp.escape.control","regexp.escape.control"]],[/\(\?#/,{token:"regexp.escape.control",next:"@regexpcomment"}],[/[()]/,"@brackets.regexp.escape.control"],[/@regexpctl/,"regexp.escape.control"],[/\\$/,"regexp.escape"],[/@regexpesc/,"regexp.escape"],[/\\\./,"regexp.invalid"],[/#/,"regexp.escape","@interpolated"]],regexrange:[[/-/,"regexp.escape.control"],[/\^/,"regexp.invalid"],[/\\$/,"regexp.escape"],[/@regexpesc/,"regexp.escape"],[/[^\]]/,"regexp"],[/\]/,"@brackets.regexp.escape.control","@pop"]],regexpcomment:[[/[^)]+/,"comment"],[/\)/,{token:"regexp.escape.control",next:"@pop"}]],pstring:[[/%([qws])\(/,{token:"string.$1.delim",switchTo:"@qstring.$1.(.)"}],[/%([qws])\[/,{token:"string.$1.delim",switchTo:"@qstring.$1.[.]"}],[/%([qws])\{/,{token:"string.$1.delim",switchTo:"@qstring.$1.{.}"}],[/%([qws])</,{token:"string.$1.delim",switchTo:"@qstring.$1.<.>"}],[/%([qws])(@delim)/,{token:"string.$1.delim",switchTo:"@qstring.$1.$2.$2"}],[/%r\(/,{token:"regexp.delim",switchTo:"@pregexp.(.)"}],[/%r\[/,{token:"regexp.delim",switchTo:"@pregexp.[.]"}],[/%r\{/,{token:"regexp.delim",switchTo:"@pregexp.{.}"}],[/%r</,{token:"regexp.delim",switchTo:"@pregexp.<.>"}],[/%r(@delim)/,{token:"regexp.delim",switchTo:"@pregexp.$1.$1"}],[/%(x|W|Q?)\(/,{token:"string.$1.delim",switchTo:"@qqstring.$1.(.)"}],[/%(x|W|Q?)\[/,{token:"string.$1.delim",switchTo:"@qqstring.$1.[.]"}],[/%(x|W|Q?)\{/,{token:"string.$1.delim",switchTo:"@qqstring.$1.{.}"}],[/%(x|W|Q?)</,{token:"string.$1.delim",switchTo:"@qqstring.$1.<.>"}],[/%(x|W|Q?)(@delim)/,{token:"string.$1.delim",switchTo:"@qqstring.$1.$2.$2"}],[/%([rqwsxW]|Q?)./,{token:"invalid",next:"@pop"}],[/./,{token:"invalid",next:"@pop"}]],qstring:[[/\\$/,"string.$S2.escape"],[/\\./,"string.$S2.escape"],[/./,{cases:{"$#==$S4":{token:"string.$S2.delim",next:"@pop"},"$#==$S3":{token:"string.$S2.delim",next:"@push"},"@default":"string.$S2"}}]],qqstring:[[/#/,"string.$S2.escape","@interpolated"],{include:"@qstring"}],whitespace:[[/[ \t\r\n]+/,""],[/^\s*=begin\b/,"comment","@comment"],[/#.*$/,"comment"]],comment:[[/[^=]+/,"comment"],[/^\s*=begin\b/,"comment.invalid"],[/^\s*=end\b.*/,"comment","@pop"],[/[=]/,"comment"]]}}});
\ No newline at end of file
/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
* Released under the MIT license
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/src/sb",["require","exports"],function(e,o){"use strict";Object.defineProperty(o,"__esModule",{value:!0}),o.conf={comments:{lineComment:"'"},brackets:[["(",")"],["[","]"],["If","EndIf"],["While","EndWhile"],["For","EndFor"],["Sub","EndSub"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]}]},o.language={defaultToken:"",tokenPostfix:".sb",ignoreCase:!0,brackets:[{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"keyword.tag-if",open:"If",close:"EndIf"},{token:"keyword.tag-while",open:"While",close:"EndWhile"},{token:"keyword.tag-for",open:"For",close:"EndFor"},{token:"keyword.tag-sub",open:"Sub",close:"EndSub"}],keywords:["Else","ElseIf","EndFor","EndIf","EndSub","EndWhile","For","Goto","If","Step","Sub","Then","To","While"],tagwords:["If","Sub","While","For"],operators:[">","<","<>","<=",">=","And","Or","+","-","*","/","="],identifier:/[a-zA-Z_][\w]*/,symbols:/[=><:+\-*\/%\.,]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[{include:"@whitespace"},[/(@identifier)(?=[.])/,"type"],[/@identifier/,{cases:{"@keywords":{token:"keyword.$0"},"@operators":"operator","@default":"variable.name"}}],[/([.])(@identifier)/,{cases:{$2:["delimiter","type.member"],"@default":""}}],[/\d*\.\d+/,"number.float"],[/\d+/,"number"],[/[()\[\]]/,"@brackets"],[/@symbols/,{cases:{"@operators":"operator","@default":"delimiter"}}],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"]],whitespace:[[/[ \t\r\n]+/,""],[/(\').*$/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"C?/,"string","@pop"]]}}});
\ No newline at end of file
/*!-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* monaco-languages version: 0.9.0(e162b4ba29044167bc7181c42b3270fa8a467424)
* Released under the MIT license
* https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md
*-----------------------------------------------------------------------------*/
define("vs/basic-languages/src/scss",["require","exports"],function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.conf={wordPattern:/(#?-?\d*\.\d\w*%?)|([@$#!.:]?[\w-?]+%?)|[@#!.]/g,comments:{blockComment:["/*","*/"],lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t.language={defaultToken:"",tokenPostfix:".scss",ws:"[ \t\n\r\f]*",identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@selector"}],selector:[{include:"@comments"},{include:"@import"},{include:"@variabledeclaration"},{include:"@warndebug"},["[@](include)",{token:"keyword",next:"@includedeclaration"}],["[@](keyframes|-webkit-keyframes|-moz-keyframes|-o-keyframes)",{token:"keyword",next:"@keyframedeclaration"}],["[@](page|content|font-face|-moz-document)",{token:"keyword"}],["[@](charset|namespace)",{token:"keyword",next:"@declarationbody"}],["[@](function)",{token:"keyword",next:"@functiondeclaration"}],["[@](mixin)",{token:"keyword",next:"@mixindeclaration"}],["url(\\-prefix)?\\(",{token:"meta",next:"@urldeclaration"}],{include:"@controlstatement"},{include:"@selectorname"},["[&\\*]","tag"],["[>\\+,]","delimiter"],["\\[",{token:"delimiter.bracket",next:"@selectorattribute"}],["{",{token:"delimiter.curly",next:"@selectorbody"}]],selectorbody:[["[*_]?@identifier@ws:(?=(\\s|\\d|[^{;}]*[;}]))","attribute.name","@rulevalue"],{include:"@selector"},["[@](extend)",{token:"keyword",next:"@extendbody"}],["[@](return)",{token:"keyword",next:"@declarationbody"}],["}",{token:"delimiter.curly",next:"@pop"}]],selectorname:[["#{",{token:"meta",next:"@variableinterpolation"}],["(\\.|#(?=[^{])|%|(@identifier)|:)+","tag"]],selectorattribute:[{include:"@term"},["]",{token:"delimiter.bracket",next:"@pop"}]],term:[{include:"@comments"},["url(\\-prefix)?\\(",{token:"meta",next:"@urldeclaration"}],{include:"@functioninvocation"},{include:"@numbers"},{include:"@strings"},{include:"@variablereference"},["(and\\b|or\\b|not\\b)","operator"],{include:"@name"},["([<>=\\+\\-\\*\\/\\^\\|\\~,])","operator"],[",","delimiter"],["!default","literal"],["\\(",{token:"delimiter.parenthesis",next:"@parenthizedterm"}]],rulevalue:[{include:"@term"},["!important","literal"],[";","delimiter","@pop"],["{",{token:"delimiter.curly",switchTo:"@nestedproperty"}],["(?=})",{token:"",next:"@pop"}]],nestedproperty:[["[*_]?@identifier@ws:","attribute.name","@rulevalue"],{include:"@comments"},["}",{token:"delimiter.curly",next:"@pop"}]],warndebug:[["[@](warn|debug)",{token:"keyword",next:"@declarationbody"}]],import:[["[@](import)",{token:"keyword",next:"@declarationbody"}]],variabledeclaration:[["\\$@identifier@ws:","variable.decl","@declarationbody"]],urldeclaration:[{include:"@strings"},["[^)\r\n]+","string"],["\\)",{token:"meta",next:"@pop"}]],parenthizedterm:[{include:"@term"},["\\)",{token:"delimiter.parenthesis",next:"@pop"}]],declarationbody:[{include:"@term"},[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],extendbody:[{include:"@selectorname"},["!optional","literal"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}]],variablereference:[["\\$@identifier","variable.ref"],["\\.\\.\\.","operator"],["#{",{token:"meta",next:"@variableinterpolation"}]],variableinterpolation:[{include:"@variablereference"},["}",{token:"meta",next:"@pop"}]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[".","comment"]],name:[["@identifier","attribute.value"]],numbers:[["(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","number.hex"]],units:[["(em|ex|ch|rem|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","number","@pop"]],functiondeclaration:[["@identifier@ws\\(",{token:"meta",next:"@parameterdeclaration"}],["{",{token:"delimiter.curly",switchTo:"@functionbody"}]],mixindeclaration:[["@identifier@ws\\(",{token:"meta",next:"@parameterdeclaration"}],["@identifier","meta"],["{",{token:"delimiter.curly",switchTo:"@selectorbody"}]],parameterdeclaration:[["\\$@identifier@ws:","variable.decl"],["\\.\\.\\.","operator"],[",","delimiter"],{include:"@term"},["\\)",{token:"meta",next:"@pop"}]],includedeclaration:[{include:"@functioninvocation"},["@identifier","meta"],[";","delimiter","@pop"],["(?=})",{token:"",next:"@pop"}],["{",{token:"delimiter.curly",switchTo:"@selectorbody"}]],keyframedeclaration:[["@identifier","meta"],["{",{token:"delimiter.curly",switchTo:"@keyframebody"}]],keyframebody:[{include:"@term"},["{",{token:"delimiter.curly",next:"@selectorbody"}],["}",{token:"delimiter.curly",next:"@pop"}]],controlstatement:[["[@](if|else|for|while|each|media)",{token:"keyword.flow",next:"@controlstatementdeclaration"}]],controlstatementdeclaration:[["(in|from|through|if|to)\\b",{token:"keyword.flow"}],{include:"@term"},["{",{token:"delimiter.curly",switchTo:"@selectorbody"}]],functionbody:[["[@](return)",{token:"keyword"}],{include:"@variabledeclaration"},{include:"@term"},{include:"@controlstatement"},[";","delimiter"],["}",{token:"delimiter.curly",next:"@pop"}]],functioninvocation:[["@identifier\\(",{token:"meta",next:"@functionarguments"}]],functionarguments:[["\\$@identifier@ws:","attribute.name"],["[,]","delimiter"],{include:"@term"},["\\)",{token:"meta",next:"@pop"}]],strings:[['~?"',{token:"string.delimiter",next:"@stringenddoublequote"}],["~?'",{token:"string.delimiter",next:"@stringendquote"}]],stringenddoublequote:[["\\\\.","string"],['"',{token:"string.delimiter",next:"@pop"}],[".","string"]],stringendquote:[["\\\\.","string"],["'",{token:"string.delimiter",next:"@pop"}],[".","string"]]}}});
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment