spring定时器
主类加
@SpringBootApplication
@MapperScan("com.example.demo.dao")
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
写个类表示定时执行
@Component
public class scheduledStart {
@Resource
private TCustomerServiceImpl customerService;
// 执行周期
@Scheduled(cron = "0/2 * * * * ?")
public void start(){
System.out.println("执行了");
customerService.updateCustomerState();
}
}
反射获取注解
@Around(value = "@annotation(com.example.demo.annotation.Purview)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// 从session域中得到对象
Object permissions = request.getSession().getAttribute("permissions");
// 转为list集合
List<String> list = MusterUtils.ObjectToListToString(permissions);
AssertUtils.isTrue(null == permissions || list.size() == 0, "权限不足!");
// 获取方法签名信息
MethodSignature signature = (MethodSignature) pjp.getSignature();
// 获取方法上的注解
Purview purview = signature.getMethod().getDeclaredAnnotation(Purview.class);
// 获取注解中的字段值
String value = purview.value();
// 不包含这个字段,返回权限不足
AssertUtils.isTrue(!list.contains(value), "权限不足!");
return pjp.proceed();
}
获取ip地址信息
并发使用,每个线程需要创建一个独立的 searcher 对象单独使用。
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>2.7.0</version>
</dependency>
仅查询
public static void main(String[] args) throws Exception {
// 数据地址
String ipdb = "src/test/resources/ip2region.xdb";
// 1. 创建searcher 对象
Searcher searcher = Searcher.newWithFileOnly(ipdb);
// 2. 查询
String ip = "162.158.166.177";
String search = searcher.search(ip);
// 打印结果
System.out.println("search = " + search); // 新加波
// 4、关闭资源
searcher.close();
}
获取详细的信息,需要使用淘宝ip库ip.taobao.com/outGetIpInf…
前后端传值
前端传数组,可以toString方法将数组转换字符串,自动带逗号,后端切割成数组
全局获得需要的资源
获取HttpServletRequest
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
记录一下,菜单控制角色
表格
create table sys_menu
(
id bigint auto_increment comment '自增ID'
primary key,
menu_name varchar(64) not null comment '菜单名',
perms varchar(100) null comment '权限标识',
parent_id int null comment '父级菜单id'
)
comment '菜单表' row_format = DYNAMIC;
代码
其中返回给前端的menvo类
public class MenuVo {
private Integer id; // id
private String parentMenu; //标签文本
private List<MenuVo> subMenu; // 子集
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MenuVo menuVo = (MenuVo) o;
return Objects.equals(id, menuVo.id) && Objects.equals(parentMenu, menuVo.parentMenu);
}
@Override
public int hashCode() {
return Objects.hash(id, parentMenu);
}
public MenuVo() {
}
@Service
@Transactional
public class SysMenuServiceImpl implements SysMenuService {
@Resource
private SysMenuMapper sysMenuMapper;
@Override
public List<MenuVo> getTreeStructure() {
LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
wrapper.orderByDesc(SysMenu::getParentId);
// 查询到的所有菜单
List<SysMenu> sysMenus = sysMenuMapper.selectList(wrapper);
// 返回给前端的树状图集合
ArrayList<MenuVo> vos = new ArrayList<>();
// 存入父级ID,为了解决同级问题
HashSet<Integer> integers = new HashSet<>();
// 遍历查询
for (SysMenu sysMenu : sysMenus) {
// 如果没有权限字符,不需要进行添加
if (StringUtils.isBlank(sysMenu.getPerms())) {
continue;
}
MenuVo menuVo = handleMenu(sysMenu, sysMenus, new MenuVo(sysMenu.getId().intValue(), sysMenu.getMenuName()), integers, vos);
if (menuVo != null) {
vos.add(menuVo);
}
}
return vos;
}
/**
*
* @param sysMenu 当前元素
* @param sysMenus 所有元素
* @param packageMenus 封装的元素
* @param integers 判断重复的id集合
* @param vos 返回前端的vo视图集合
*/
private MenuVo handleMenu(SysMenu sysMenu, List<SysMenu> sysMenus, MenuVo packageMenus, HashSet<Integer> integers, ArrayList<MenuVo> vos) {
integers.add(sysMenu.getId().intValue());
// 创建集合存储子集信息
ArrayList<MenuVo> newMenu = new ArrayList<>();
// 如果为没有父级目录返回当前封装的集合
if (sysMenu.getParentId() == null) return packageMenus;
// 查出来父级的菜单信息
SysMenu menu = findMenuById(sysMenu.getParentId(), sysMenus);
// 如果未找到抛出异常
AssertUtils.isTrue(menu == null, "数据库脏数据,请联系管理员!");
// 将查找的元素放入集合
MenuVo mv = new MenuVo();
mv.setId(menu.getId().intValue());
mv.setParentMenu(menu.getMenuName());
// 添加时判断是否存在子元素(不断替换 packageMenus中的子元素信息)
newMenu.add(packageMenus);
mv.setSubMenu(newMenu);
packageMenus = mv;
// 要判断查出来的父级id是否已经存在过了
if (integers.contains(menu.getId().intValue())) {
addOwnedList(packageMenus, vos);
return null;
}
integers.add(sysMenu.getParentId());
// 继续遍历 没有父级菜单则返回
return menu.getParentId() == null ? packageMenus : handleMenu(menu, sysMenus, packageMenus, integers, vos);
}
/**
* 添加到对应的集合中
*/
private void addOwnedList(MenuVo packageMenus, List<MenuVo> vos) {
for (MenuVo vo : vos) {
// 如果一致,则表示需要将 索引0的元素添加到 vos中对应的位置
if (vo.getId().equals(packageMenus.getId())) {
vo.getSubMenu().add(packageMenus.getSubMenu().get(0));
return;
} else {
// 否则继续递归查询
if (vo.getSubMenu() != null && vo.getSubMenu().size() != 0)
addOwnedList(packageMenus, vo.getSubMenu());
}
}
}
// 根据id找到对应菜单
private SysMenu findMenuById(Integer id, List<SysMenu> sysMenus) {
for (SysMenu sysMenu : sysMenus) {
if (sysMenu.getId().intValue() == id) {
return sysMenu;
}
}
return null;
}
SpingBoot 整合 druid
依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.16</version>
</dependency>
yml 配置
spring:
datasource:
druid:
url: jdbc:mysql://localhost:3306/mu_xin
username: root
password: 1234
initial-size: 5 # 初始连接数 (重要)
min-idle: 5 # 最小空闲连接数 (重要)
max-active: 20 # 最大活跃连接数 (重要)
max-wait: 60000 # 获取连接的最大等待时间 (重要)
time-between-eviction-runs-millis: 6000 # 定期验证连接的间隔时间 (重要)
min-evictable-idle-time-millis: 300000 # 连接在池中最小生存的时间 (不重要)
# Druid配置
validation-query-timeout: 5 # 验证查询的超时时间 (重要)
test-while-idle: true # 在连接空闲期间测试连接的有效性 (重要)
test-on-borrow: false # 在从连接池中获取连接时是否进行测试 (不重要)
test-on-return: false # 在归还连接给连接池时是否进行测试 (不重要)
pool-prepared-statements: true # 是否缓存预编译语句 (不重要)
max-pool-prepared-statement-per-connection-size: 20 # 每个连接在缓存中可缓存的预编译语句的最大数量 (不重要)
filters: stat,wall,log4j2 # Druid的过滤器列表 (不重要)
明文加密
依赖
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
// 生成盐
String gensalt = BCrypt.gensalt();
// 密码加密
String hashpw = BCrypt.hashpw("123456", gensalt);
// 验证
BCrypt.checkpw("123456", "$2a$10$Ccvo9cVvXKDVmpL/Op0npOpTZQZmKBDcsuCUmCCgfDi1bz.no33xO");
克隆
BeanUtils.copyProperties(克隆源, 克隆到目标);
若依添加登录方式
项目需要添加新的登录方式,需要与平台登录隔离开
@PostMapping("/ar_login")
public AjaxResult ar_login(@NotBlank(message = "请求参数有误") String username) {
HashSet<String> permiss = new HashSet<>();
// 权限集合
Collections.addAll(permiss, "ar_check:pending_approval:list", "ar_check:inspection:edit", "ar_check:device:query",
"ar_check:defects:add");
LoginUser loginUser = new LoginUser(user, permiss);
SysUser user = new SysUser();
user.setUserName("kun");
loginUser.setUser(user);
// 创建 Authentication 对象
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
loginUser, null, loginUser.getAuthorities());
// 设置用户信息到 SecurityContext 中
SecurityContextHolder.getContext().setAuthentication(authentication);
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = tokenService.createToken(loginUser);
ajax.put(Constants.TOKEN, token);
return ajax;
}
后台启动 jar
命令
javaw -jar xxxxxxx.jar
关闭
任务管理器打开详细信息, 找到 javaw 关闭
SpringBoot 关闭 web端口
- 去除 web 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 端口设置 -1,禁用 tomcat
server:
port: -1
spring:
main:
web-application-type: none # 禁用
SpringBoot 整合Logback 日志
根目录文件 logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--
CONSOLE :表示当前的日志信息是可以输出到控制台的。
-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--输出流对象 默认 System.out 改为 System.err-->
<target>System.out</target>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %green(%5level) --- [%t] %c [%thread] : %msg%n</pattern>
</encoder>
</appender>
<!-- File是输出的方向通向文件的 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n)</pattern>
<charset>utf-8</charset>
</encoder>
<!--日志输出路径-->
<file>C:/codeLigh/Lightning-data.log</file>
<!--指定日志文件拆分和压缩规则-->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--通过指定压缩文件名称,来确定分割文件方式-->
<fileNamePattern>C:/codeLigh/Lightning-data2-%d{yyyy-MMdd}.log%i.gz</fileNamePattern>
<!--文件拆分大小-->
<maxFileSize>15MB</maxFileSize>
</rollingPolicy>
</appender>
<!--
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
, 默认debug
<root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
-->
<!-- 这里是输出配置,console表示在控制台输出,删除就没有了-->
<root level="ALL">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
Spring Boot 打包 EXE
- 安装地址:exe4j.apponic.com/ (傻瓜式安装,一直下一步就行了)
激活:L-g782dn2d-1f1yqxx1rv1sqd
主界面:可以 open 打开加载的配置
选择 JAR 转 EXE
配置程序名称和存放路径
配置实例和应用信息
勾上 64 位系统
从不使用DPI
配置编码:在VM参数配置的地方加上:-Dfile.encoding=utf-8
选择 jar包
配置jre版本
这样打包,可以把jre打包,不用再按照jdk