XML 文件的解析
常见的解析工具有 DOM4j、JDOM 等,为了标准化 XML 文件解析,Java 中提出了 JAXP 规范,使用的解析模
型有
优点:操作方便,可以对文档进行 CRUD 的所有操作
缺点:一次性加载进入内存形成 DOM 树,非常消耗资源
优点:不消耗资源
缺点:只能读取,不能增删改
public class Test2 {
public static void main(String[] args) throws Exception {
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = parserFactory.newSAXParser();
final List<Student> studentList = new ArrayList<Student>();
saxParser.parse("students.xml", new DefaultHandler() {
private Student student=null;
private int flag=0;
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("student".equals(qName)) {
student=new Student();
String id=attributes.getValue("id");//获取当前标签的指定名称的属性
if(id!=null && id.trim().length()>0)
student.setId(id);
}else if("name".equals(qName))
flag=1;
else if("age".equals(qName))
flag=2;
else if("sex".equals(qName))
flag=3;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String tmp = new String(ch, start, length);
if(tmp!=null && tmp.trim().length()>0){
if(flag==1)
student.setName(tmp.trim());
else if(flag==2){
Integer kk=Integer.parseInt(tmp.trim());
student.setAge(kk);
}else if(flag==3)
student.setSex(tmp.trim());
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
flag=0;
if("student".equals(qName))
studentList.add(student);
}
});
studentList.forEach(System.out::println);
}
}
早期数据传输使用 xml 作为交互格式,例如 webservice 技术,但是由于 xml 解析比较麻烦,所以现在在项目开发中,在接口与接口之间以及前后端之间数据的传输都使用 Json 格式,在 Spring Boot 中接口返回 Json 格式的数据很简单,在 Controller 中使用@RestController 注解即可返回 Json 格式的数据,@RestController 也是Spring Boot 新增的一个复合注解。
源代码:其中 Target、Retention 和 Documented 是元注解
@Target({ElementType.TYPE}) 用于声明注解可以使用在什么地方,Type 表示可以使用在类上
@Retention(RetentionPolicy.RUNTIME) 用于声明注解需要保持到什么阶段,Runtime 表示注解在编译生成的字节码中一直保持到运行时
@Documented
@Controller
@ResponseBody
public @interface RestController {
String value() default "";
}
可 以看 出@RestController 注 解包 含 了 原来 的 @Controller 和@ResponseBody 注 解, 使 用 过 Spring 对@Controller 注解用于声明当前类是控制器类,@ResponseBody 注解是将返回的数据结构转换为 Json 格式。
所以在默认情况下,使用了@RestController 注解即可将返回的数据结构转换成 Json 格式,Spring Boot 中默认使用的 Json 解析技术框架是 jackson。点开 pom.xml 中的 spring-boot-starter-web 依赖,可以看到一个
spring-boot-starter-json 依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jsonartifactId>
<scope>compilescope>
dependency>
Spring Boot 中对依赖都做了很好的封装,可以看到很多 spring-boot-starter-xxx 系列的依赖,这是 Spring Boot的特点之一,不需要人为去引入很多相关的依赖了,starter-xxx 系列直接都包含了所必要的依赖,所以再次点进去上面这个 spring-boot-starter-json 依赖,可以看到:
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<scope>compilescope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatypegroupId>
<artifactId>jackson-datatype-jdk8artifactId>
<scope>compilescope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatypegroupId>
<artifactId>jackson-datatype-jsr310artifactId>
<scope>compilescope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.modulegroupId>
<artifactId>jackson-module-parameter-namesartifactId>
<scope>compilescope>
dependency>
到此为止知道了 Spring Boot 中默认使用的 json 解析框架是 jackson。默认的 jackson 框架对常用数据类型的转 Json 处理。
在实际项目中,常用的数据结构无非有类对象、List 对象、Map 对象,默认的 jackson 框架对这三个常用的数据结构都可以转成 json 的格式。
需要创建一个实体类 User。
public class User {
private Long id;
private String username;
private String password;
/* 省略 get、set 和带参构造方法 */
}
然后创建一个 Controller,分别返回 User 对象、List
和 Map
.
@RestController
@RequestMapping("/json")
public class JsonController {
@RequestMapping("/user")
public User getUser() {
return new User(1, "羊羊", "123456");
}
@RequestMapping("/list")
public List<User> getUserList() {
List<User> userList = new ArrayList<>();
User user1 = new User(1, "羊羊", "123456");
User user2 = new User(2, "小灰灰", "123456");
userList.add(user1);
userList.add(user2);
return userList;
}
@RequestMapping("/map")
public Map<String, Object> getMap() {
Map<String, Object> map = new HashMap<>(3);
User user = new User(1, "羊羊", "123456");
map.put("作者信息", user);
map.put("博客地址", "http://blog.yang.com");
map.put("CSDN 地址", "http://blog.csdn.net/羊羊");
map.put("粉丝数量", 4153);
return map;
}
}
写好了接口,分别返回了一个 User 对象、一个 List 集合和一个 Map 集合,其中 Map 集合中的 value 存的是不同的数据类型
在浏览器中输入:localhost:8080/json/user 返回 json:
{“id”:1,“username”:“羊羊”,“password”:“123456”}
在浏览器中输入:localhost:8080/json/list 返回 json:
[{“id”:1, “username”:“羊羊”, “password”:“123456”}, {“id”:2, “username”:“小灰灰”, “password”:“123456”}]
在浏览器中输入:`localhost:8080/json/map 返回 json:
{" 作 者 信 息 " : {“id”:1, “username”:" 羊羊", “password”:“123456”}, "CSDN 地 址 " :
“http://blog.csdn.net/yangyang”, “粉丝数量”:4153, “博客地址”:“http://blog.yang.com”}
可以看出 map 中不管是什么数据类型,都可以转成相应的 json 格式,这样就非常方便。
在实际项目中,难免会遇到一些 null 值出现,转 json 时是不希望有这些 null 出现的,比如期望所有的 null 在转 json 时都变成""这种空字符串,那怎么做呢?在 Spring Boot 中做一下配置即可,新建一个 jackson 的配置类:
@Configuration 用于声明当前类是一个配置类,最新的注解为@SpringBootConfiguration
public class JacksonConfig {
@Bean //用于在配置类中,表示方法的返回值是一个受管 bean
@Primary //如果多个配置,则以当前的为主
@ConditionalOnMissingBean(ObjectMapper.class)
//条件注解,表示如果受管 bean 中没有 ObjectMapper类型的对象,则需要构建
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
jsonGenerator.writeString(""); 针对 null 内容输出空字符串
}
});
return objectMapper;
}
}
//然后修改一下上面返回 map 的接口,将几个值改成 null 测试一下:
@RequestMapping("/map")
public Map<String, Object> getMap() {
Map<String, Object> map = new HashMap<>(3);
User user = new User(1, "羊羊", null);
map.put("作者信息", user);
map.put("博客地址", "http://blog.yang.com");
map.put("CSDN 地址", null);
map.put("粉丝数量", 4153);
return map;
}
重启项目再次输入 localhost:8080/json/map,可以看到 jackson 已经将所有 null 字段转成了空字符串了。例如
返回数据为{“作者信息”:{“id”:1,“username”:“羊羊”,“password”:“”},“CSDN 地址”:“”,“粉丝数量”:4153,“博客地址”:“http://blog.yang.com”}
配置属性不参与映射输出
@JsonIgnore //指定该属性不参与 JSON 字符串的映射
private String password;
//配置日期类型数据的映射格式
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birth=new Date();
通用 mapper 就是基于 mybatis 的一款 MyBatis 增强插件,可以提供一些常用增、删、改、查的操作,不需要重复写一些常用的 sql。简化操作,精简代码,并且达到代码风格统一的目的。它的出现不是为了替代 mybatis,
而是让 mybatis 的开发更方便。
添加依赖:
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
<version>4.2.2version>
dependency>
使用通用 mapper 的开发方式,采用注解定义映射关系,自动生成常见的 SQL 语句,不需要 xml 映射元文件
1.表名默认使用类名,驼峰转下划线(只对大写字母进行处理),如 TestUser 默认对应的表名为 test_user
2.表名可以使用@Table(name = “tableName”)进行指定,对不符合第一条默认规则的可以通过这种方式指定表名.
3.字段默认和@Column 一样,都会作为表字段,表字段默认为 Java 对象的 Field 名字驼峰转下划线形式.
4.可以使用@Column(name = “fieldName”)指定不符合第 3 条规则的字段名
5.使用@Transient 注解可以忽略字段,添加该注解的字段不会作为表字段使用.
6.建议一定是有一个@Id 注解作为主键的字段,可以有多个@Id 注解的字段作为联合主键.
7.默认情况下,实体类中如果不存在包含@Id 注解的字段,所有的字段都会作为主键字段进行使用(这种效率极低).
8.实体类可以继承使用,可以参考测试代码中的 tk.mybatis.mapper.model.UserLogin2 类.
9.由于基本类型,如 int 作为实体类字段时会有默认值 0,而且无法消除,所以实体类中建议不要使用基本类型.
10.@NameStyle 注解,用来配置对象名/字段和表名/字段之间的转换方式,该注解优先于全局配置 style,可选值:
normal:使用实体类名/属性名作为表名/字段名
camelhump:这是默认值,驼峰转换为下划线形式
uppercase:转换为大写
lowercase:转换为小写
@Data
@Entity //用于声明当前类是一个实体类
@Table(name="tbl_users") // 用于声明当前类所对应的表名称
public class User implements Serializable {
@Id //用于声明标识属性,对应表中的主键
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column //如果属性名称和列名称不一致,则需要通过@Column进行配置对应的列名称
private String username;
private String password;
@JsonFormat(pattern = "yyyy-M-d")
private Date birth;
private Boolean sex;
}
定义 mapper 接口
@Repository
public interface UserMapper extends BaseMapper<User> {
@Select("select * from tbl_users where username=#{username}")
List<User> selectByUsername(String username);
}
针对 mapper 接口进行注册,一般是依赖自动扫描实现。可以在主类或者配置上添加一个注解配置
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;
@MapperScan(basePackages = "com.ma.dao")
@SpringBootApplication
public class CommonMapperApplication {
public static void main(String[] args) {
SpringApplication.run(CommonMapperApplication.class, args);
}
}
SpringBoot 针对 Junit 的单元测试有很好的支持
@SpringBootTest
class CommonMapperApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
}
@Test
void testCreate(){
User user=new User();
user.setUsername("周芷若");
user.setPassword("666666");
user.setSex(true);
int len = userMapper.insertSelective(user);
Assertions.assertEquals(1,len);
}
}
需要控制器调用业务,业务再通过 Mapper 访问数据库,最终返回 JSON 字符串