认识Spring Boot
Spring Boot是什么
从 2002 年开始,Spring 一直在飞速的发展。Spring Boot 是伴随着 Spring 4.0 诞生的,到今天 Spring Boot 的版本已经到了 3.2.0。Spring是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具,它集成了大量常用的第三方库配置,Spring Boot 应用中这些第三方库几乎可以是零配置的开箱即用 out of thebox,大部分的 Spring Boot 应用都只需要非常少量的 Java 配置代码,开发者能够更加专注于业务逻辑。
Spring Boot的优点
- 1、减少开发,测试时间和努力。
- 2、使用 JavaConfig 有助于避免使用 XML。
- 3、避免大量的 Maven 导入和各种版本冲突。
- 4、提供意见发展方法。
- 5、通过提供默认值快速开始开发。
- 6、没有单独的 Web 服务器需要。这意味着你不再需要启动 Tomcat,Glassfish 或其他任何东西。
- 7、需要更少的配置因为没有 web.xml 文件。只需添加用 Configuration 注释的类,然后添加用 Bean 注释的方法,Spring 将自动加载对象并像以前一样对其进行管理。您甚至可以将 Autowired 添加到 bean 方法中,以使Spring 自动装入需要的依赖关系中。
- 8、基于环境的配置使用这些属性,可以将正在使用的环境传递到应用程序:例如命令行参数配置值为-Dspring.profiles.active={enviornment} 。 在 加 载 主 应 用 程 序 属 性 文 件 后 , Spring 将 在(application-{environment}.properties)中加载后续的应用程序属性文件。
Spring Boot是如何简化配置的
Spring Boot 更多的是采用 Java Config的方式,对 Spring 进行配置。新建一个类但是不用加@Service 注解,也就是说,它是个普通的类,只需要加上@Configuration 和@Bean 两个注解即可实现成为一个 Bean 并且让 Spring去管理。
一个普通类:
public class TestService {
public String sayHello () {
return "Hello Spring Boot!";
}
}
对应的配置类:
@Configuration
public class JavaConfig {
@Bean
public TestService getTestService() {
return new TestService();
}
}
@Configuration 表示该类是个配置类,@Bean 表示该方法返回一个 Bean。这样可以把 TestService 作为 Bean 让Spring 去管理了,在其他地方如果需要使用该 Bean,和原来一样,直接使用@Resource 注解注入进来即可使用,非常方便。
@Resource
private TestService testService;
另外部署配置方面,原来 Spring 有多个 xml 和 properties 配置,在 Spring Boot 中只需要个 application.yml即可。
Spring Boot简化部署
在使用Spring时项目部署时需要在服务器上部署 tomcat,然后把项目打成war 包扔到 tomcat 里,在使用Spring Boot 后,不需要在服务器上去部署 tomcat,因为 Spring Boot 内嵌了 tomcat,只需要将项目打成 jar 包,然后使用 java -jar xxx.jar 一键式启动项目。另外,也降低对运行环境的基本要求,环境变量中有 JDK 即可。
Spring Boot简化监控
可以引入 spring-boot-start-actuator 依赖,直接使用 REST 方式来获取进程的运行期性能参数,从而达到监控的目的,比较方便。但是 Spring Boot 只是个微框架,没有提供相应的务发现与注册的配套功能,没有外围监控集成方案,没有外围安全管理方案,所以在微服务架构中,还需要 Spring Cloud 来配合一起使用。
Spring Boot工程的构建
IDEA 快速构建
IDEA 中可以通过 File->New->Project 来快速构建 Spring Boot 工程。选择 Spring Initializr,在 Project SDK 中选择刚刚导入的 jdk,点击 Next,到了项目的配置信息。
Group:填企业域名,一般采用域名反装的方式定义,例如使用 com.zhu
Artifact:填项目名称,例如工程名 demo,如果项目规模较大这里可能会采用模块名称
Dependencies:可以添加项目中所需要的依赖信息,根据实际情况来添加,这里只需要选择 Web 即可。
官方构建
1、访问 http://start.spring.io/或者 http://start.aliyun.com/。
2、在页面上输入相应的 Spring Boot 版本、Group 和 Artifact 信息以及项目依赖,然后创建项目。
3、下载解压后,使用 IDEA 导入该 maven 工程:File->New->Model from Existing Source,然后选择解压后的项目文件夹即可。如果是使用 eclipse 可以通过 Import->Existing Maven Projects->Next,然后选择解压后的项目文件夹即可。
Spring Boot 返回 Json 数据
XML 文件的解析
常见的解析工具有 DOM4j、JDOM 等,为了标准化 XML 文件解析,Java 中提出了 JAXP 规范,使用的解析模型有:
- 1.DOM:将标记语言文档一次性加载进入内存中,在内存中形成一颗 DOM 树(服务器端常用)
- 优点:操作方便,可以对文档进行 CRUD 的所有操作
- 缺点:一次性加载进入内存形成 DOM 树,非常消耗资源
- 2.SAX:逐行读取,基于事件驱动(安卓终端常用)
- 优点:不消耗资源
- 缺点:只能读取,不能增删改
早期数据传输使用 xml 作为交互格式,例如 webservice 技术,但是由于 xml 解析比较麻烦,所以现在在项目开发中,在接口与接口之间以及前后端之间数据的传输都使用 Json 格式,在 Spring Boot 中接口返回 Json 格式的数据很简单,在 Controller 中@RestController 注解即可返回 Json 格式的数据,@RestController 也是Spring Boot 新增的一个复合注解。
注解配置
@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。
Spring Boot 默认对 Json 的处理
创建 User 实体类
public class User {
private Long id;
private String username;
private String password;
/* 省略 get、set 和带参构造方法 */
}
创建 Controller 类
@RestController
@RequestMapping("/test3")
public class Test3Controller {
@RequestMapping(value = "/json1",method = {RequestMethod.GET,RequestMethod.POST})
public User load(){
User res=new User();
res.setId(1L);
res.setUsername("张三");
res.setPassword("333333");
return res;
}
@GetMapping("/json2")
public List<User> load2(){
List<User> userList=new ArrayList<>();
for(int i=0;i<5;i++){
User tmp=new User();
tmp.setId(10L+i);
tmp.setUsername("name_"+i);
userList.add(tmp);
}
return userList;
}
@GetMapping("/json3")
public Map<String,User> load3(){
Map<String,User> res=new LinkedHashMap<>();
for(int i=0;i<5;i++){
User tmp=new User();
tmp.setId(10L+i);
tmp.setUsername("name_"+i);
res.put("id_"+i,tmp);
}
return res;
}
}
写好了接口,分别返回了一个 User 对象、一个 List 集合和一个 Map 集合,其中 Map 集合中的 value 存的是不同的数据类型。
jackson 中对 null 的处理
实际项目中,难免会遇到一些 null 值出现,转 json 时是不希望有这些 null 出现的,比如期望所有的 null 在转 json 时都变成""这种空字符串。解决该问题只需在 Spring Boot 中做一下配置即可:
@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.yan.com");
map.put("CSDN 地址", null);
map.put("粉丝数量", 4153);
return map;
}
配置属性不参与映射输出
@JsonIgnore 指定该属性不参与 JSON 字符串的映射
private String password;
配置日期类型数据的映射格式
@JsonFormat(pattern = "yyyy-MM-dd")
private Date birth=new Date();
整合通用 Mapper 的开发方法
添加依赖:
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>4.2.2</version>
</dependency>
使用通用 mapper 的开发方式,采用注解定义映射关系,自动生成常见的 SQL 语句,不需要 xml 映射源文件。
实体类
@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;
private Date birth;
private Boolean sex;
}
定义 mapper 接口
public interface UserMapper extends BaseMapper<User> {
}
针对 mapper 接口进行注册,一般是依赖自动扫描实现。可以在主类或者配置上添加一个注解配置
@MapperScan(basePackages="com.zhu.dao")
@SpringBootApplication
public class JsonApplication {
public static void main(String[] args) {
SpringApplication.run(JsonApplication.class, args);
}
}
使用阿里巴巴 FastJson 的设置
有很多人已经习惯于使用阿里巴巴的 fastJson 来做项目中 json 转换的相关工作,比如目前项目中使用的就是阿里的 fastJson。
fastJson 依赖导入
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
使用 fastJson 处理 null
@Configuration
public class fastJsonConfig extends WebMvcConfigurationSupport {
//使用阿里 FastJson 作为 JSON MessageConverter
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters ) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
SerializerFeature.WriteMapNullValue, // 保留 map 空的字段
SerializerFeature.WriteNullStringAsEmpty, // 将 String 类型的 null 转成"" SerializerFeature.WriteNullNumberAsZero, // 将 Number 类型的 null 转成 0
SerializerFeature.WriteNullListAsEmpty, // 将 List 类型的 null 转成[]
SerializerFeature.WriteNullBooleanAsFalse, // 将 Boolean 类型的 null 转成 false
SerializerFeature.DisableCircularReferenceDetect); // 避免循环引用
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
List<MediaType> mediaTypeList = new ArrayList<>();
// 解决中文乱码问题,相当于在 Controller 上的@RequestMapping 中加了个属性 produces =
"application/json" mediaTypeList.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypeList);
converters.add(converter);
}
}
封装统一返回的数据结构
在实际项目中,除了要封装数据之外,往往需要在返回的 json 中添加一些其他信息,比如返回一些状态码 code【注意不是 response 的响应状态码】,返回一些 msg 给调用者,这样调用者可以根据 code 或者 msg 做一些逻辑判断。所以在实际项目中,需要封装一个统一的 json 返回结构存储返回信息。
定义统一的 json 结构
由于封装的 json 数据的类型不确定,所以在定义统一的 json 结构时需要用到泛型。统一的 json 结构中属性包括数据、状态码、提示信息即可,构造方法可以根据实际业务需求做相应的添加即可,一般来说,应该有默认的返回结构,也应该有用户指定的返回结构。
对 Spring Boot 中 json 数据的返回做了详细的分析,从 Spring Boot 默认的 jackson 框架到阿里的fastJson 框架,分别对它们的配置做了相应的描述。另外,结合实际项目情况,总结了实际项目中使用的 json
封装结构体,加入了状态码和提示信息,使得返回的 json 数据信息更加完整。