SpringBoot-2

1、Spring Boot 返回 Json 数据

XML 文件的解析

常见的解析工具有 DOM4j、JDOM 等,为了标准化 XML 文件解析,Java 中提出了 JAXP 规范,使用的解析模

型有

  1. DOM:将标记语言文档一次性加载进入内存中,在内存中形成一颗 DOM 树(服务器端常用)
  • 优点:操作方便,可以对文档进行 CRUD 的所有操作

  • 缺点:一次性加载进入内存形成 DOM 树,非常消耗资源

  1. SAX:逐行读取,基于事件驱动(安卓终端常用)
  • 优点:不消耗资源

  • 缺点:只能读取,不能增删改

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 处理。

2、Spring Boot 默认对 Json 的处理

在实际项目中,常用的数据结构无非有类对象、List 对象、Map 对象,默认的 jackson 框架对这三个常用的数据结构都可以转成 json 的格式。

2.1创建 User 实体类

需要创建一个实体类 User。

public class User {
    private Long id;
    private String username;
    private String password;
    /* 省略 get、set 和带参构造方法 */
}

2.2 创建 Controller 类

然后创建一个 Controller,分别返回 User 对象、ListMap.

@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;
    }
}

2…3 测试不同数据类型返回的 json

写好了接口,分别返回了一个 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 格式,这样就非常方便。

2.4 jackson 中对 null 的处理

在实际项目中,难免会遇到一些 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();

3、整合通用 Mapper 的开发方法

通用 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 字符串

你可能感兴趣的:(spring,boot,java,后端)