正反代理
正向代理
代理的是客户端,如国内访问国外网站,有防火墙限制,我们可以通过VPN去访问;
反向代理
代理的是服务器,如机房内多个后端服务,通过Nginx对外提供服务;
Nginx
- 默认配置文件
nginx.conf
nginx单点问题
可以结合
keepalived
解决单点问题
public class MyHandler implements ElementHandler {
// xml中每一个<节点>开始执行的方法
@Override
public void onStart(ElementPath elementPath) {
// todo 解析xml要做的业务处理
}
// xml中每一个<节点>结束执行的方法
@Override
public void onEnd(ElementPath elementPath) {
// todo 解析xml要做的业务处理
elementPath.getCurrent().detach();
}
}
// 获取当前解析的<节点>是第几级,根节点为第1级
public static int getLevel(ElementPath path) {
return path.getPath().split("/").length - 1;
}
// 获取当前节点的节点名
public static String getElementName(Element element) {
return element.getName();
}
// 获取当前节点属性
public static String getAttribute(Element element) {
return element.attribute("attribute-name");
}
// 获取当前节点文本
public static String getText(Element element) {
return element.getText();
}
<!-- 要解析的xml格式 -->
<root>
<book id="1">
<name>菜鸟编程</name>
<describe>针对菜鸟编程学习</describe>
</book>
<book id="2">
<name>老鸟编程</name>
<describe>针对老鸟编程学习</describe>
</book>
</root>
// book映射对象
@Data
public class Book {
private int id;
private String name;
private String describe;
}
// 解析book.xml伪代码
public class BookHandler implements ElementHandler {
// 创建一个Book对象
private Book book;
// xml中每一个<节点>开始执行的方法
@Override
public void onStart(ElementPath elementPath) {
// 获取节点级数,<root>为1,<book>为2,<name><describe>为3
level = getLevel(elementPath)
switch(level):
case 1: // 不做处理
case 2: // 每次读取到<book id="xx">这一行会执行
// 创建book对象,将读取的id属性写入
book = new Book();
book.setId();
case 3: // 每次读取到<book>的子节点会执行
// 无需处理
}
// xml中每一个<节点>结束执行的方法
@Override
public void onEnd(ElementPath elementPath) {
// 获取节点级数,<root>为1,<book>为2,<name><describe>为3
level = getLevel(elementPath)
switch(level):
case 1: // 不做处理
case 2: // 每次读取到</book>这一行会执行
// 说明这一本书所有信息已经读完,需要将book对象保存,或写入数据库,然后清空
saveDB(book); // 保存数据方法
book = null;
case 3: // 每次读完一个<book>的子节点会执行
// 可以读取book的name、describe属性,并写入到book对象中
// 注意 一次只能获取到一个属性,要做一些处理
String name = getAttribute("name");
String describe = getAttribute("describe");
book.setName(name);
book.setDescribe(describe);
elementPath.getCurrent().detach();
}
}
// 读取xml,使用BookHandler解析
BookHandler bookHandler = new BookHandler();
SAXReader reader = new SAXReader();
reader.setDefaultHandler(bookHandler);
reader.read(new File(xmlPath));
DOM4J
是一个开源XML
解析包。DOM4J
应用于Java
平台,采用了Java
集合框架并完全支持DOM
、SAX
、xpath
、JAXP
。
接口 | 说明 |
---|---|
Attribute |
属性 |
Branch |
分支,指能够包含子节点的节点。如Element ,(Docuemnts ) |
CDATA |
XML CDATA 区域 |
CharacterData |
是一个标识接口,标识基于字符的节点。如CDATA ,Comment , Text |
Comment |
注释 |
Document |
文档 |
DocumentType |
XML DOCTYPE 声明 |
Element |
定义XML 元素 |
ElementHandler |
Element 对象的处理器 |
ElementPath |
被ElementHandler 使用,用于取得当前正在处理的路径层次信息 |
Entity |
定义XML entity |
Node |
节点 |
NodeFilter |
节点过滤器 |
ProcessingInstruction |
定义XML 处理指令 |
Text |
文本节点 |
Visitor |
用于实现Visitor 模式 |
XPath |
XPath 表达式 |
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--dom4j使用xpath依赖的包-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File(filename)); //读取XML文件,获得document对象
// Document document = saxReader.read(url);
Linux diff命令用于比较文件的差异。
diff以逐行的方式,比较文本文件的异同处。如果指定要比较目录,则diff会比较目录中相同文件名的文件,但不会比较其中子目录。
diff <文件1> <文件2> [附加参数]
diff test1.txt test2.txt
-b
或--ignore-space-change
不检查空格字符的不同-B
或--ignore-blank-lines
不检查空白行-c
显示全部内文,并标出不同之处-H
或--speed-large-files
比较大文件时,可加快速度-i
或--ignore-case
不检查大小写的不同-y
或--side-by-side
以并列的方式显示文件的异同之处-W
<宽度>或--width
<宽度> 在使用-y参数时,指定栏宽|
表示前后2个文件内容有不同<
表示后面文件比前面文件少了1行内容>
表示后面文件比前面文件多了1行内容使用MyBatis查询 返回类型为int,但是当查询结果为空NULL,报异常的解决方法
如
select pre_id from task_child where parent_id=3 order by pre_id desc limit 1;
如果查询结果是空,那么后台可能报异常
Servlet.service() for servlet [springDispatcherServlet] in context with path [/xxxx] threw exception [Request processing failed;
nested exception is org.apache.ibatis.binding.BindingException: Mapper method 'com.xxx.PersonRoleRelationMapper.getPersonRecordno attempted to return null from a method with a primitive return type (int).]
with root cause org.apache.ibatis.binding.BindingException: Mapper method 'com.xxx.PPersonRoleRelationMapper.getPersonRecordno attempted to return null from a method with a primitive return type (int).
这时,我们需要给查询结果一个默认值
select IFNULL(MAX(pre_id),-1) from task_child where parent_id=3 order by pre_id desc limit 1;
或者
-- 在Oracle中我们可以这样写:
select NVL(max(pre_id),0) ...
--对于所有数据库适用的方法可以这样写:
select COALESCE(max(pre_id),0) ...
max也可以用sum函数代替.
spring boot
通过注解@EnableScheduling
和@Scheduled
实现的是静态定时任务,不能动态添加、停止、修改等.
本文通过ThreadPoolTaskScheduler
实现定时任务动态增删改.
ThreadPoolTaskScheduler
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(10);
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
return threadPoolTaskScheduler;
}
@Data
public class Tasks {
public static Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();
}
public class MyRunnable implements Runnable {
private String id;
public MyRunnable(String id) {
this.id = id;
}
@Override
public void run() {
System.out.println("id: " + this.id + " - " + new Date());
}
}
任务的元数据信息可以保存在数据库中.
@RestController
public class DynamicTask {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
// 增加一个带id的定时任务
@RequestMapping("/start")
public String startCron(@RequestParam("id") String id) {
if (Tasks.tasks.containsKey(id)) {
return "exist";
}
ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(new MyRunnable(id), new CronTrigger("0/5 * * * * *"));
Tasks.tasks.put(id, future);
return "start";
}
//根据id删除一个定时任务
@RequestMapping("/stop")
public String stopCron(@RequestParam("id") String id) {
if (!Tasks.tasks.containsKey(id)) {
return "not exist";
}
Tasks.tasks.get(id).cancel(true);
Tasks.tasks.remove(id);
return "stop";
}
//根据id修改定时任务
@RequestMapping("/changeCron10")
public String startCron10(@RequestParam("id") String id) {
stopCron(id);// 先停止,在开启.
ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(new MyRunnable(id), new CronTrigger("*/10 * * * * *"));
Tasks.tasks.put(id, future);
return "change";
}
}