1. Properties文件操作实战指南
在Java开发中,Properties文件是一种常见的配置文件格式,它以键值对的形式存储数据,扩展名通常为.properties。这种文件格式特别适合存储简单的配置信息,比如数据库连接参数、系统配置项等。
1.1 Properties文件基础特性
Properties文件本质上是一个Map集合(键值对集合),但它有自己独特的用途和操作方式:
- 每行表示一个键值对,格式为
key=value - 支持使用
#或!开头的注释行 - 默认使用ISO 8859-1字符编码,处理中文时需要转义
- 值部分可以跨行,使用反斜杠()作为续行符
Properties类位于java.util包中,是Hashtable的子类,提供了专门用于读写.properties文件的方法。
1.2 Properties文件读取实战
让我们通过一个完整案例来掌握Properties文件的读取操作。假设我们有一个users.properties文件,内容如下:
code复制admin=123456
赵敏=wuji
张无忌=zhaomin
灰太狼=xiyangyang
对应的Java读取代码如下:
java复制public class PropertiesDemo01 {
public static void main(String[] args) throws Exception {
// 1. 创建Properties对象
Properties prop = new Properties();
// 2. 加载属性文件
prop.load(new FileReader("src/com/javabase/d1_properties/users.properties"));
// 3. 打印整个属性集
System.out.println(prop);
// 4. 根据键获取值
System.out.println(prop.getProperty("admin"));
// 5. 遍历所有键值对
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
String value = prop.getProperty(key);
System.out.println(key + "=" + value);
}
// 6. 使用Lambda表达式遍历
prop.forEach((k,v) -> System.out.println(k + "====>" + v));
}
}
注意事项:文件路径建议使用相对路径,并且要注意转义字符。在Windows系统中,路径分隔符需要使用双反斜杠
\\或者正斜杠/。
1.3 Properties文件写入操作
除了读取,我们还需要掌握如何将数据写入Properties文件。下面是一个写入操作的示例:
java复制public class PropertiesDemo02 {
public static void main(String[] args) throws Exception {
// 1. 创建Properties对象
Properties prop = new Properties();
// 2. 设置属性
prop.setProperty("玄冥二老", "wangfei");
prop.setProperty("tom", "jay");
prop.setProperty("金毛狮王", "成昆");
// 3. 存储到文件
prop.store(new FileWriter("src/com/javabase/d1_properties/users1.properties"),
"lots of users");
}
}
store()方法的第二个参数是注释,会写入到文件顶部。如果不需要注释,可以传入null。
1.4 修改Properties文件中的值
实际开发中,经常需要修改配置文件中的某些值。下面是一个修改特定键值对的示例:
java复制public class PropertiesTest {
public static void main(String[] args) throws Exception {
// 1. 创建Properties对象
Properties prop = new Properties();
// 2. 加载文件
prop.load(new FileReader("src/com/javabase/d1_properties/people.txt"));
// 3. 修改特定键的值
if(prop.containsKey("李芳")) {
prop.setProperty("李芳", "18");
}
// 4. 重新存储到文件
prop.store(new FileWriter("src/com/javabase/d1_properties/people.txt"), "");
}
}
实操心得:修改Properties文件时,一定要先加载原文件内容,修改后再整体写回,否则会丢失原有内容。这种"读取-修改-写入"的模式是处理配置文件的通用做法。
2. XML文件处理技术详解
XML(Extensible Markup Language)是一种可扩展的标记语言,它被设计用来传输和存储数据。与Properties文件相比,XML更适合存储复杂的数据结构。
2.1 XML基础语法规则
一个标准的XML文件需要遵循以下规则:
- 文档声明必须是第一行:
<?xml version="1.0" encoding="UTF-8"?> - 有且只有一个根元素
- 标签必须正确嵌套
- 标签名区分大小写
- 属性值必须用引号括起来
- 特殊字符需要使用实体引用(如
<代表<)
示例XML文件:
xml复制<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="1">
<name>张三</name>
<age>20</age>
<gender>男</gender>
</student>
<student id="2">
<name>李四</name>
<age>22</age>
<gender>女</gender>
</student>
</students>
2.2 使用Dom4j解析XML
Dom4j是一个优秀的Java XML API,具有性能优异、功能强大和易用的特点。下面是使用Dom4j解析XML的完整流程:
- 下载Dom4j jar包并添加到项目依赖中
- 创建SAXReader对象
- 读取XML文件获取Document对象
- 通过Document对象获取根元素
- 遍历元素树获取所需数据
示例代码:
java复制public class Dom4jTest01 {
public static void main(String[] args) throws Exception {
// 1. 创建SAXReader对象
SAXReader saxReader = new SAXReader();
// 2. 读取XML文件
Document doc = saxReader.read("src/Contact.xml");
// 3. 获取根元素
Element rootElement = doc.getRootElement();
System.out.println("根元素名称:" + rootElement.getName());
// 4. 获取所有子元素
List<Element> contacts = rootElement.elements("contact");
for (Element contact : contacts) {
System.out.println("联系人ID:" + contact.attributeValue("id"));
System.out.println("姓名:" + contact.elementText("name"));
System.out.println("性别:" + contact.elementText("gender"));
System.out.println("邮箱:" + contact.elementText("email"));
}
}
}
2.3 XML数据封装与处理
实际开发中,我们通常会将XML数据转换为Java对象进行处理。下面是一个将XML联系人数据封装为Java对象的示例:
java复制@Data
@AllArgsConstructor
@NoArgsConstructor
public class Contact {
private String name;
private int id;
private String email;
private char gender;
}
public class Dom4jTest02 {
public static void main(String[] args) throws Exception {
SAXReader saxReader = new SAXReader();
Document doc = saxReader.read("src/Contacts.xml");
Element rootElement = doc.getRootElement();
List<Contact> contacts = new ArrayList<>();
List<Element> contactElements = rootElement.elements("contact");
for (Element element : contactElements) {
Contact contact = new Contact();
contact.setId(Integer.parseInt(element.attributeValue("id")));
contact.setName(element.elementTextTrim("name"));
contact.setEmail(element.elementTextTrim("email"));
contact.setGender(element.elementTextTrim("gender").charAt(0));
contacts.add(contact);
}
contacts.forEach(System.out::println);
}
}
注意事项:使用elementTextTrim()方法可以去除文本内容两端的空白字符,避免因格式问题导致的数据异常。
2.4 XML文件生成技术
虽然Dom4j可以用于生成XML文件,但在简单场景下,直接拼接XML字符串可能更高效:
java复制public class Dom4jTest03 {
public static void main(String[] args) throws Exception {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
sb.append("<contacts>\r\n");
sb.append(" <contact id=\"1\">\r\n");
sb.append(" <name>张无忌</name>\r\n");
sb.append(" <gender>男</gender>\r\n");
sb.append(" <email>wuji@itcast.cn</email>\r\n");
sb.append(" </contact>\r\n");
sb.append("</contacts>");
try (PrintStream out = new PrintStream("src/Contacts1.xml")) {
out.println(sb);
}
}
}
对于复杂XML生成需求,建议使用Dom4j的DocumentHelper类创建Document对象,然后通过addElement()等方法构建XML结构,最后使用XMLWriter输出到文件。
3. 日志技术深度解析
日志是软件开发中不可或缺的部分,它记录了系统运行时的各种信息,对于调试、监控和问题排查都至关重要。
3.1 日志技术体系
Java日志体系主要包含以下几个组成部分:
- 日志接口:SLF4J、JCL
- 日志实现:Logback、Log4j2、JUL
- 桥接器:解决不同日志框架之间的兼容问题
目前主流的组合是SLF4J + Logback,因为:
- SLF4J提供了良好的接口抽象
- Logback性能优异,是Log4j的升级版
- 两者由同一作者开发,兼容性好
3.2 Logback快速入门
要使用Logback,需要在项目中添加以下依赖:
- slf4j-api (日志接口)
- logback-core (Logback核心)
- logback-classic (Logback经典实现)
基础使用示例:
java复制public class Test {
private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
try {
LOGGER.info("除法开始了...");
divide(10, 2);
LOGGER.info("除法成功了...");
} catch (Exception e) {
LOGGER.error("除法执行失败了:" + e.getMessage());
}
}
public static void divide(int a, int b) {
LOGGER.debug("参数a:{}", a);
LOGGER.debug("参数b:{}", b);
int result = a / b;
LOGGER.info("结果:{}", result);
}
}
3.3 Logback配置详解
Logback的配置文件logback.xml通常放在src目录下,主要配置内容包括:
- 日志输出级别:TRACE < DEBUG < INFO < WARN < ERROR
- 日志输出目的地:控制台、文件、数据库等
- 日志格式:时间、级别、线程、类名、消息等
- 日志文件滚动策略:按时间、按大小
典型配置示例:
xml复制<configuration>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/application.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志级别设置 -->
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>
3.4 日志使用最佳实践
-
合理选择日志级别:
- TRACE/DEBUG:开发调试使用
- INFO:重要业务流程信息
- WARN:潜在问题
- ERROR:错误异常
-
日志内容要包含足够上下文:
- 避免只有"操作失败"这样的模糊信息
- 记录相关参数和状态信息
-
使用参数化日志:
java复制// 推荐 LOGGER.debug("User {} login from {}", username, ip); // 不推荐 LOGGER.debug("User " + username + " login from " + ip); -
异常处理:
java复制try { // 业务代码 } catch (Exception e) { LOGGER.error("处理用户{}订单时出错", userId, e); }
经验分享:在实际项目中,建议为不同的业务模块创建不同的Logger实例,这样可以更灵活地控制各个模块的日志级别。同时,要注意日志文件的大小和保留策略,避免日志文件占用过多磁盘空间。