桥下の民 - Java基础
type: channel
link: https://wordplay.work/index.php/category/Java基础
items: Allatori 代码混淆
items: Java ThreadPool
items: IDEA 部署 Web 项目
items: 对象思想
items: 悲观锁(行锁) & 乐观锁
items: Lambda 表达式
items: LocalDateTime & Date
items: cookie & session
items: tomcat 配置文件 web.xml 解析

Allatori 代码混淆
type: item
date: 2023-06-16T10:12:00+00:00
description: 一、Allatori Allatori 是一个 Java 混淆器，它属于第二代混淆器，因此它能够全方位地保护你的知识产权。 Allatori 具有以下几种保护方式：命名混淆，流混淆，调试信息混淆，字符串混淆，以及水印技术。对于教育和非商业项目来说这个混淆器是免费的。支持 war 和 jar 文件格式，并且允许对需要混淆代码的应用程序添加有效日期。 有项目需要对代码进行保护，比较初级的方案就是对代码进行混淆，打包之后的文件进行反编译后，就可以看到效果。此外，使用 Allatori 打的包体积也会小一点。 官网：http://www.allatori.com/ 二、简单混淆 解压找到目录: Allatori-8.6-Demo\tutorial\step01\files。 Clean.bat config.xml 配置文件 mousegestures-1.2.jar MouseGesturesObfuscated.bat MouseGesturesOriginal.bat RunAllatori.bat 双击生成混淆的jar test.jar 混淆前的jar 如果你只有一个项目，并且混淆次数也不多，你也可以通过这种方式，把项目拷贝到这个目录，修改配置文件，手动执行混淆的脚本。 三、多项目集成idea 2.1、lib 文件夹添加 allatori.jar allatori-annotations.jar 2.2、pom.xml <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-and-filter-allatori-config</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${basedir}/target</outputDirectory> <resources> <resource> <directory>src/main/resources/config</directory> <includes> <include>allatori.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <id>run-allatori</id> <phase>package</phase> <goals> <goal>exec</goal> </goals> </execution> </executions> <configuration> <executable>java</executable> <arguments> <argument>-Xms128m</argument> <argument>-Xmx512m</argument> <argument>-jar</argument> <argument>../lib/allatori.jar</argument> <argument>${basedir}/target/allatori.xml</argument> </arguments> </configuration> </plugin> </plugins> </build> 2.3、allatori.xml <config> <jar in="web-api-1.0.jar" out="web-obfuscated.jar"/> <ignore-classes> <class template="class *Application*"/> <class te…

Java ThreadPool
type: item
date: 2023-02-28T06:57:00+00:00
description: 线程池 ThreadPoolExecutor public class ThreadPoolExample { public static void main(String[] args) { // 创建自定义线程工厂 ThreadFactory customeThreadFactory = new ThreadFactory() { private final AtomicInteger count = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setName("自定义线程-" + count.getAndIncrement()); return thread; } }; ThreadPoolExecutor executor = new ThreadPoolExecutor( 1, // 核心线程数 2, // 最大线程数 60L, // 临时线程空闲存活时间 TimeUnit.SECONDS, new LinkedBlockingQueue<>(2),// 队列容量 customeThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy()// 触发拒绝策略（CallerRunsPolicy） ); // 提交任务 for (int i = 0; i < 10; i++) { final int taskId = i; executor.submit(() -> { System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId); return taskId; }); } // 关闭线程池 executor.shutdown(); } } 处理流程： 第1个任务： 创建核心线程处理（1个核心线程） 第2、3个任务： 进入队列等待（队列容量2个） 第4个任务： 创建临时线程处理（最大线程数2 - 核心线程数1 = 1个临时线程） 第5个任务： 触发拒绝策略（CallerRunsPolicy） 在调用者线程中执行 临时线程： keepAliveTime = 60L // 临时线程空闲存活时间 临时线程在空闲超过60秒后会被回收。 核心线程默认不回收。 可以通过 allowCoreThreadTimeOut(true) 允许回收核心线程。 如何设置合适的参数： 如何设置合适的参数 核心线程数设置考虑因素： CPU密集型：通常设置为CPU核心数+1 IO密集型：可以设置为CPU核心数*2 混合型：CPU核心数（1+平均等待时间/平均工作时间） 最大线程数设置考虑因素： 系统内存大小 任务的响应时间要求 任务的类型（CPU密集或IO密集） 示例配置 // CPU密集型配置 int cpuCores = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor cpuIntensiveExecutor = new ThreadPoolExecutor( cpuCores + 1, // 核心线程数 cpuCores + 1, // 最大线程数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000) ); // IO密集型配置 ThreadPoolExecutor ioIntensiveExecutor = new ThreadPoolExecutor( cpuCores * 2, // 核心线程数 cpuCores * 4, // 最大线程数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2000) ); 核心线程用于处理正常负载。 临时线程用于处理突发负载。 参数设置需要根据实际业务场景调整和测试。 CallerRunsPolicy 的作用： 流量控制 当线程池满载时，让调用者自己执行任务。 这会降低任务提交的速度。 起到自然的背压作用。 防止任务丢失 不像 DiscardPolicy 直接丢弃任务。 不像 AbortPolicy 抛出异常。 确保任务最终会被执行。 优缺点 优点：不会丢失任务。 缺点：可能会影响调用者线程的响应时间。

IDEA 部署 Web 项目
type: item
date: 2022-09-02T06:43:00+00:00
description: 1、新建好 web 模块后，在 module 里面要添加进去 2、libraries 下点 +，选择 java，把这个模块的 lib 目录添加，lib 中包含所需要的的各种 jar 包 3、生成 war exploded 包，选择你要运用到的模块 4、facets 中添加 web 模块，确认好路径，path 要定位到 web.xml 目录下，web resource 要定位到 web 目录下 5、配置 tomcat 命名推荐改为你当前的模块/项目名。 deployment 选择上面步骤生成的 war 包。 url 中 8080/ 后的目录要和 deployment 里面 applicationContext 吻合。

对象思想
type: item
date: 2022-07-07T02:25:00+00:00
description: 一、PO : persistent object 持久对象 1、有时候也被为 Data 对象，对应数据库中的 entity，可以简单认为一个 PO 对应数据库中的一条记录。 2、在 hibernate 持久化框架中与 insert/delet 操作密切相关。 3、PO 中不应该包含任何对数据库的操作。 持久化对象，它跟持久层（通常是关系型数据库）的数据结构形成一一对应的映射关系，如果持久层是关系型数据库，那么，数据表中的每个字段（或若干个）就对应 PO 的一个（或若干个）属性。 二、POJO : plain ordinary java object 无规则简单 java 对象 使用 POJO 名称是为了避免和 EJB 混淆起来, 而且简称比较直接。其中有一些属性及其 getter setter 方法的类，没有业务逻辑，有时可以作为 VO(value-object) 或 DTO(Data Transform Object) 来使用.当然，如果你有一个简单的运算属性也是可以的，但不允许有业务方法，也不能携带有 connection 之类的方法。 POJO 是 Plain Old Java Objects 的缩写不错，但是它通指没有使用 Entity Beans 的普通 java 对象，可以把 POJO 作为支持业务逻辑的协助类。 POJO 有一些 private 的参数作为对象的属性。然后针对每个参数定义了 get 和 set 方法作为访问的接口。 POJO 是 MartinFowler 等发明的一个术语，用来表示普通的 Java 对象，不是 JavaBean, EntityBean 或者 SessionBean。 POJO 不担当任何特殊的角色，也不实现任何特殊的 Java 框架的接口如，EJB， JDBC 等等。 即 POJO 是一个简单的普通的 Java 对象，它不包含业务逻辑或持久逻辑等，但不是 JavaBean、EntityBean 等，不具有任何特殊角色和不继承或不实现任何其它 Java 框架的类或接口。 一个中间对象，可以转化为 PO、DTO、VO。 1、POJO 持久化之后 ==〉PO 在运行期，由 Hibernate 中的 cglib 动态把 POJO 转换为 PO，PO 相对于 POJO 会增加一些用来管理数据库 entity 状态的属性和方法。PO 对于 programmer 来说完全透明，由于是运行期生成 PO，所以可以支持增量编译，增量调试。 2、POJO 传输过程中 ==〉DTO 3、POJO 用作表示层 ==〉VO 三、BO : business object 业务对象 封装业务逻辑为一个对象（可以包括多个 PO，通常需要将 BO 转化成 PO，才能进行数据的持久化，反之，从 DB 中得到的 PO，需要转化成 BO 才能在业务层使用）。 关于 BO 主要有三种概念 1、只包含业务对象的属性； 2、只包含业务方法； 3、两者都包含。 在实际使用中，认为哪一种概念正确并不重要，关键是实际应用中适合自己项目的需要。 四、VO : value object 值对象 / view object表现层对象 1、主要对应页面显示（web 页面 / swt、swing 界面）的数据对象。 2、可以和表对应，也可以不，这根据业务的需要。 注 ：在 struts 中，用 ActionForm 做 VO，需要做一个转换，因为PO是面向对象的，而 ActionForm 是和 view 对应的，要将几个 PO 要显示的属性合成一个 ActionForm，可以使用 BeanUtils 的 copy 方法。 五、DTO（TO） : Data Transfer Object 数据传输对象 1、用在需要跨进程或远程传输时，它不应该包含业务逻辑。 2、比如一张表有100个字段，那么对应的PO就有100个属性（大多数情况下，DTO 内的数据来自多个表）。但 view 层只需显示10个字段，没有必要把整个 PO 对象传递到 client，这时我们就可以用只有这10个属性的 DTO 来传输数据到 client，这样也不会暴露 server 端表结构。到达客户端以后，如果用这个对象来对应界面显示，那此时它的身份就转为 VO。 六、DAO : data access object 数据访问对象 1、主要用来封装对 DB 的访问（CRUD 操作）。 2、通过接收 Business 层的数据，把 POJO 持久化为 PO。 七、DO（Domain Object） : 领域对象，就是从现实世界中抽象出来的有形或无形的业务实体。 八、区别 8.1、POJO 和 JaveBean 的区别 POJO 的内在含义是指那些没有从任何类继承、也没有实现任何接口，更…

悲观锁(行锁) & 乐观锁
type: item
date: 2022-07-04T07:40:00+00:00
description: 实现并发控制的主要手段分为乐观并发控制和悲观并发控制两种。 乐观锁比较适用于读多写少的情况(多读场景)，悲观锁比较适用于写多读少的情况(多写场景)。 一、悲观锁(Pessimistic Lock) 1.1、理解 当要对数据库中的一条数据进行修改的时候，为了避免同时被其他人修改，最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制，在修改数据之前先锁定，再修改的方式被称之为悲观并发控制 Pessimistic Concurrency Control，缩写 PCC，又名悲观锁。 悲观锁，具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务，以及来自外部系统的事务处理)修改持保守态度。因此，在整个数据处理过程中，将数据处于锁定状态。悲观锁的实现，往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性，否则，即使在本系统中实现了加锁机制，也无法保证外部系统不会修改数据)。 之所以叫做悲观锁，是因为这是一种对数据的修改持有悲观态度的并发控制方式。总是假设最坏的情况，每次读取数据的时候都默认其他线程会更改数据，因此需要进行加锁操作，当其他线程想要访问数据时，都需要阻塞挂起。悲观锁的实现： 传统的关系型数据库使用这种锁机制，比如行锁、表锁、读锁、写锁等，都是在操作之前先上锁。 Java 里面的同步 synchronized 关键字的实现。 1.2、悲观锁主要分为共享锁和排他锁： 共享锁 shared locks 又称为读锁，简称 S 锁。顾名思义，共享锁就是多个事务对于同一数据可以共享一把锁，都能访问到数据，但是只能读不能修改。 排他锁 exclusive locks 又称为写锁，简称 X 锁。顾名思义，排他锁就是不能与其他锁并存，如果一个事务获取了一个数据行的排他锁，其他事务就不能再获取该行的其他锁，包括共享锁和排他锁。获取排他锁的事务可以对数据行读取和修改。 1.3、说明 悲观并发控制实际上是 先取锁再访问 的保守策略，为数据处理的安全提供了保证。但是在效率方面，处理加锁的机制会让数据库产生额外的开销，还有增加产生死锁的机会。另外还会降低并行性，一个事务如果锁定了某行数据，其他事务就必须等待该事务处理完才可以处理那行数据。 二、乐观锁(Optimistic Locking) 2.1、理解 乐观锁是相对悲观锁而言的，乐观锁假设数据一般情况不会造成冲突，所以在数据进行提交更新的时候，才会正式对数据的冲突与否进行检测，如果冲突，则返回给用户异常信息，让用户决定如何去做。乐观锁适用于读多写少的场景，这样可以提高程序的吞吐量。 乐观锁采取了更加宽松的加锁机制。也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制，但乐观锁不会刻意使用数据库本身的锁机制，而是依据数据本身来保证数据的正确性。乐观锁的实现： CAS 实现：Java 中 java.util.concurrent.atomic 包下面的原子变量使用了乐观锁的一种 CAS 实现方式。 版本号控制：一般是在数据表中加上一个数据版本号 version 字段，表示数据被修改的次数。当数据被修改时，version 值会 +1。当线程 A 要更新数据时，在读取数据的同时也会读取 version 值，在提交更新时，若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新，否则重试更新操作，直到更新成功。 2.2、说明 乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的，因此尽可能直接做下去，直到提交的时候才去锁定，所以不会产生任何锁和死锁。 三、具体实现 3.1、悲观锁实现方式 悲观锁的实现，往往依靠数据库提供的锁机制。在数据库中，悲观锁的流程如下： 在对记录进行修改前，先尝试为该记录加上排他锁(exclusive locks)。 如果加锁失败，说明该记录正在被修改，那么当前查询可能要等待或者抛出异常。具体响应方式由开发者根据实际需要决定。 如果成功加锁，那么就可以对记录做修改，事务完成后就会解锁了。 期间如果有其他对该记录做修改或加排他锁的操作，都会等待解锁或直接抛出异常。 以 MySql Innodb 引擎举例，说明 SQL 中悲观锁的应用 要使用悲观锁，必须关闭 MySQL 数据库的自动提交属性set autocommit=0。因为 MySQL 默认使用 autocommit 模式，也就是说，当执行一个更新操作后，MySQL 会立刻将结果进行提交。 以电商下单扣减库存的过程说明一下悲观锁的使用： 使用 select…for update 锁数据，需要注意锁的级别，MySQL InnoDB 默认行级锁。行级锁都是基于索引的，如果一条 SQL 语句用不到索引是不会使用行级锁…

Lambda 表达式
type: item
date: 2022-03-31T03:26:00+00:00
description: 1、filer public void test01() { List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1); // 遍历输出符合条件的元素 list.stream().filter(x -> x > 6).forEach(System.out::println); // 匹配第一个 Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst(); // 匹配任意（适用于并行流） // 串行流：适合存在线程安全问题、阻塞任务、重量级任务，以及需要使用同一事务的逻辑。 // 并行流：适合没有线程安全问题、较单纯的数据处理任务。 Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny(); // 是否包含符合特定条件的元素 boolean anyMatch = list.stream().anyMatch(x -> x < 6); System.out.println("匹配第一个值：" + findFirst.get()); System.out.println("匹配任意一个值：" + findAny.get()); System.out.println("是否存在大于6的值：" + anyMatch); } 2、to list public class Person { private String name; // 姓名 private int salary; // 薪资 private int age; // 年龄 private String sex; // 性别 private String area; // 地区 } public void test03() { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("Tom", 8900, 23, "male", "New York")); personList.add(new Person("Jack", 7000, 25, "male", "Washington")); personList.add(new Person("Lily", 7800, 21, "female", "Washington")); personList.add(new Person("Anni", 8200, 24, "female", "New York")); personList.add(new Person("Owen", 9500, 25, "male", "New York")); personList.add(new Person("Alisa", 7900, 26, "female", "New York")); List<String> fiterList = personList.stream().filter(x -> x.getSalary() > 8000).map(Person::getName) .collect(Collectors.toList()); System.out.print("高于8000的员工姓名：" + fiterList); } 3、max public void test04() { List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd"); Optional<String> max = list.stream().max(Comparator.comparing(String::length)); System.out.println("最长的字符串：" + max.get()); } 4、sort public void test05() { List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6); // 自然排序 Optional<Integer> max = list.stream().max(Integer::compareTo); // 自定义排序 Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1.compa…

LocalDateTime & Date
type: item
date: 2022-03-25T16:21:00+00:00
description: JDK1.8 版本中引入了 DateTime API，加强了对时间的管理。 一、Date 存在的缺陷 Date 如果不格式化，打印出的日期可读性差,如下所示。 Tue Sep 10 09:34:04 CST 2019 所以通常会使用SimpleDateFormate来实现格式化，但是SDF最大的问题是线程不安全的。 private StringBuffer format(Date var1, StringBuffer var2, FieldDelegate var3) { this.calendar.setTime(var1); boolean var4 = this.useDateFormatSymbols(); int var5 = 0; calendar 是共享变量，并且这个共享变量没有做线程安全控制。当多个线程同时使用相同的 SimpleDateFormat 对象【如用 static 修饰的 SimpleDateFormat】调用 format 方法时，多个线程会同时调用 calendar.setTime 方法，可能一个线程刚设置好 time 值另外的一个线程马上把设置的 time 值给修改了导致返回的格式化时间可能是错误的。 多线程并发如何保证线程安全： 1、避免线程之间共享一个 SimpleDateFormat 对象，每个线程使用时都创建一次 SimpleDateFormat 对象 => 创建和销毁对象的开销大。对使用 format 和 parse 方法的地方进行加锁 => 线程阻塞性能差。 2、使用 ThreadLocal 保证每个线程最多只创建一次 SimpleDateFormat 对象 => 较好的方法。 3、Date 对时间处理比较麻烦，比如想获取某年、某月、某星期，以及n天以后的时间，如果用 Date 来处理的话真是太难了，你可能会说 Date 类不是有 getYear、getMonth 这些方法吗，获取年月日很Easy，但是这些方法都被弃用了。 二、LocalDateTime 使用 JDK8 带来了新的时间日期 API 也就是 java.time 包下面带来 Local 和 Zone，两者的区别一个是基于你本地时间的，一个是你自己指定时区的。 而 Local 都有这几个类：LocalDateTime（既包含时间也包含日期），LocalDate（只关注日期，一般来说你只关注日期不需要时间的话用这个），LocalTime（只关注时间，不关注日期）。 当然了，实际上 LocalDate 和 LocalTime 也支持日期+时间的形式，因为 LocalDate 里面包含一个 atTime 来存储时间，同理 LocalTime 也有一个 atDate 属性 例如： LocalDate localDate = LocalDate.of(2021,3,15); localDate.atTime(LocalTime.now()); 但是如果不想多设置的话可以直接使用 LocalDateTime，将日期时间一起处理了。 LocalDateTime localDateTime = LocalDateTime.now(); 所以说 LocalDateTime 取代 Date 是一个趋势，当然有人比较过二者的效率，结果是 Date 要比 LocalDateTIme 快一些，这也没办法毕竟线程安全可能就要多点取舍，未来的版本也许 LocalDateTime 也可以像 Current 集合那样线程又安全又快。

cookie & session
type: item
date: 2022-03-05T13:51:00+00:00
description: 一、Cookie Cookie 数据是由客户端来保存和携带的，所以称之为客户端技术。 创建一个 cookie，cookie 是 servlet 发送到 Web 浏览器的少量信息。这些信息由浏览器保存，然后发送回服务器 cookie 的值可以唯一地标识客户端，因此 cookie 常用于会话管理。 一个 cookie 拥有一个名称、一个值和一些可选属性，比如注释、路径和域限定符、最大生存时间和版本号。一些 Web 浏览器在处理可选属性方面存在 bug，因此有节制地使用这些属性可提高 serviet 的互操作性。 servlet 通过使用 HttpServletResponse#addCookie 方法将 cookie 发送到浏览器：该方法将字段添加到 HTTP 响应头以便一次一个地将 cookie 发送到浏览器。浏览器应该支持每台 Web 服务器有 20 个 cookie，总共有 300 个 cookie，并且可能将每个 cookie 的大小限定为 4 KB。 浏览器通过向 HTTP 请求头添加字段将 cookie 返回给 serlet 可使用 HttpServletRequest#getCookies 方法从请求中获取 cookie。一些 cookie 可能有相同的名称，但却有不同的路径属性。 cookie 影响使用它们的 Web 页面的缓存。HTTP 1.0 不会缓存那些使用通过此类创建的 cookie 的页面。此类不支持 HTTP 1.1 中定义的缓存控件。 此类支持版本0(遵守Netscape协议)和版本1(遵守RFC 2109协议) cookie 规范。默认情况下, cookie 是使用版本0创建的,以确保最佳互操作性。 cookie 容量：一个浏览器最多保存 300 个 cookie。每个站点做多保存 20 个 cookie，每个 cookie 的大小限制是 4kb。 cookie 默认存活时间：浏览器关闭的时候结束。 cookie 持久化：若希望浏览器将 cookie 存储到磁盘上就需要用到 maxAge()，以秒为单位的时间。 cookie 删除：删除 cookie 时，path 必须一致，否则不会被删除。 属性： 1、name：名称不能唯一确定一个 Cookie。路径可能不同。 2、value：不能存中文。 3、path：默认值是写 Cookie 的那个程序的访问路径。 比如：http://localhost:8080/day10_00_cookie/servlet/login写的 Cookie path 就是：/day10_00_cookie 看当前创建 cookie 的资源（servlet）文件路径 也可以是 reuest.getContextPath(); 获取当前应用的路径。 客户端在访问服务器另外资源时，根据访问的路径来决定是否带着 Cookie 到服务器。 当前访问的路径如果是以 cookie 的 path 开头的路径，浏览器就带。否则不带。 4、maxAge(有效存活时间)：cookie 的缓存时间。默认是 -1（默认存在浏览器的内存中）。单位是秒。 负数：cookie的数据存在浏览器缓存中。 0：删除。路径要保持一致，否则可能删错人。 正数：缓存（持久化到磁盘上）的时间。 cookie 在磁盘上持久化的文本形式： cookie 在磁盘上持久化的文本形式： public class CookieDemo1 extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter pw = resp.getWriter(); Cookie[] cookies = req.getCookies(); for (int i = 0;cookies!=null&& i < cookies.length; i++) { if("lastAccessTime".equals(cookies[i].getName())) { long l = Long.parseLong(cookies[i].getValue()); pw.write("您上次的登陆时间为:"+new Date(l).toLocaleString()); } } //删除cookie跳转的servlet pw.print("clear cookie"); //创建cookie Cookie ck = new Cookie(…

tomcat 配置文件 web.xml 解析
type: item
date: 2022-03-05T13:28:00+00:00
description: 一、示例 ?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.core.AprLifecycleListener" /> <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/> <GlobalNamingResources> <Environment name="simpleValue" type="java.lang.Integer" value="30"/> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <!-- 每个Service元素只能有一个Engine元素.元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求 name:Service服务器的名称 --> <Service name="Catalina"> <!-- Connector元素: 由Connector接口定义.<Connector>元素代表与客户程序实际交互的组件,它负责接收客户请求,以及向客户返回响应结果. --> <Connector port="80" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" /> <!-- 属性说明 port:服务器连接器的端口号,该连接器将在指定端口侦听来自客户端的请求。 enableLookups:如果为true，则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名； 若为false则不进行DNS查询，而是返回其ip地址。 redirectPort:服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号。 acceptCount:当所有可以使用的处理请求的线程都被用光时,可以放到处理队列中的请求数,超过这个数的请求将不予处理，而返回Connection refused错误。 connectionTimeout:等待超时的时间数（以毫秒为单位）。 maxThreads:设定在监听端口的线程的最大数目,这个值也决定了服务器可以同时响应客户请求的最大数目.默认值为200。 protocol:必须设定为AJP/1.3协议。 address:如果服务器有两个以上IP地址,该属性可以设定端口监听的IP地址,默认情况下,端口会监听服务器上所有IP地址。 minProcessors:服务器启动时创建的处理请求的线程数，每个请求由一个线程负责。 maxProcessors:最多可以创建的处理请求的线程数。 minSpareThreads:最小备用线程 。 maxSpareThreads:最大备用线程。 debug:日志等级。 disableUploadTimeout:禁用上传超时,主要用于大数据上传时。 --> <Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" /> <Engine name="Catalina" defaultHost="localhost"> <!-- 属性说明 name:对应…