SpringBoot提供默认配置来帮助我们快速创建一个直接运行的单体Spring应用
特性:
- tomcat:内置的tomcat、Jetty
- starter pom:提供大量默认的starter pom来构建配置
- 自动配置能力:根据类路径中的jar包、bean定义和各种属性源来自动配置
- CLI:提供命令行界面(CLI)工具和Actuator模块,方便应用的管理和监控
推荐一个很好的学习教程,spring boot要如何学习?_学springboot需要学spring吗-CSDN博客
1 构建hello world工程
MAVEN构建
- pom.xml
parent、starter、test、web
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
构建一个简单的hello world工程就遇到了两个坑,第一个springboot只会扫描启动类所在包的类和子包的类;
第二个是写测试类的时候发现@SpringApplicationConfiguration这个注解已经被取消掉了,使用@SpringBootTest这个注解
- 属性文件
在src/main/resources目录创建一个application.properties
-
定义Controller
package com.didispace.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String index() {
return "Hello World";
}
}
- 启动类
package com.didispace;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Chapter1Application {
public static void main(String[] args) {
SpringApplication.run(Chapter1Application.class, args);
}
}
- 测试
package com.didispace;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.didispace.web.HelloController;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MockServletContext.class)
@WebAppConfiguration
public class Chapter1ApplicationTests {
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();
}
@Test
public void getHello() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(equalTo("Hello World")));
System.out.println("OK");
}
}
2 属性、随机数、多环境配置
属性文件application.properties
在application.properties中定义随机数:net.csdn.chapter1.number=${random.int}
多环境配置:在application.properties中定义spring.profiles.active=prod,那么会加载application-prod.properties文件中配置的属性
3 创建一套简单的restfulapi,单元测试
- User.java
package cc.bean;
public class User {
private Long id;
private String name;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
- UserController.java
package cc.controller;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import cc.bean.User;
@RestController
@RequestMapping(path="/users")
public class UserController {
static Map<Long,User> userMap = Collections.synchronizedMap(new HashMap<Long,User>());
@RequestMapping(path="/",method=RequestMethod.GET)
public List<User> getUserList(){
List<User> userList = new ArrayList<User>(userMap.values());
return userList;
}
@RequestMapping(path="/",method=RequestMethod.POST)
public String addUser(@ModelAttribute User user){
userMap.put(user.getId(), user);
return "success";
}
@RequestMapping(path="/{id}",method=RequestMethod.GET)
public User getUser(@PathVariable Long id){
return userMap.get(id);
}
@RequestMapping(path="/{id}",method=RequestMethod.PUT)
public String addUser(@PathVariable Long id,@ModelAttribute User user){
User u = userMap.get(user.getId());
u.setName(user.getName());
u.setAge(user.getAge());
userMap.put(u.getId(), u);
return "success";
}
@RequestMapping(path="/{id}",method=RequestMethod.DELETE)
public String delUser(@PathVariable Long id){
userMap.remove(id);
return "success";
}
}
- UserControllerTest.java
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import cc.Chapter2Application;
import cc.controller.UserController;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Chapter2Application.class)
@WebAppConfiguration
public class UserControllerTest {
private MockMvc mvc;
@Before
public void setUp() {
mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
}
@Test
public void testUserController() throws Exception {
// 测试UserController
RequestBuilder request = null;
// 1、get查一下user列表,应该为空
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[]")));
// 2、post提交一个user
request = post("/users/")
.param("id", "1")
.param("name", "测试大师")
.param("age", "20");
mvc.perform(request)
// .andDo(MockMvcResultHandlers.print())
.andExpect(content().string(equalTo("success")));
// 3、get获取user列表,应该有刚才插入的数据
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[{\"id\":1,\"name\":\"测试大师\",\"age\":20}]")));
// 4、put修改id为1的user
request = put("/users/1")
.param("name", "测试终极大师")
.param("age", "30");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));
// 5、get一个id为1的user
request = get("/users/1");
mvc.perform(request)
.andExpect(content().string(equalTo("{\"id\":1,\"name\":\"测试终极大师\",\"age\":30}")));
// 6、del删除id为1的user
request = delete("/users/1");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));
// 7、get查一下user列表,应该为空
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[]")));
}
}
除了可以用JUNIT做单元测试外,还可以用火狐浏览器Rested Client插件发送http请求。
4 springboot-mybatis简单整合
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springboot</groupId>
<artifactId>springboot-mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>springboot-mybatis整合</description>
<!-- Spring Boot 启动父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Boot Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 热交换 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Mybatis 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<!-- MySQL 连接驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
- application.properties
## 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=a123
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
## Mybatis 配置
mybatis.typeAliasesPackage=org.spring.springboot.domain
mybatis.mapperLocations=classpath:mapper/*.xml
-
CityMapper.xml
mybatis映射文件,在src\main\resources\mapper目录创建一个CityMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="org.spring.springboot.dao.CityDao">
<resultMap id="BaseResultMap" type="org.spring.springboot.domain.City">
<result column="id" property="id" />
<result column="province_id" property="provinceId" />
<result column="city_name" property="cityName" />
<result column="description" property="description" />
</resultMap>
<parameterMap id="City" type="org.spring.springboot.domain.City"/>
<sql id="Base_Column_List">
id, province_id, city_name, description
</sql>
<select id="findByName" resultMap="BaseResultMap" parameterType="java.lang.String">
select
<include refid="Base_Column_List" />
from city
where city_name like '%${cityName}%'
</select>
</mapper>
- entity、dao、service、controller
package org.spring.springboot.domain;
/**
* 城市实体类
*
*/
public class City {
/**
* 城市编号
*/
private Long id;
/**
* 省份编号
*/
private Long provinceId;
/**
* 城市名称
*/
private String cityName;
/**
* 描述
*/
private String description;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getProvinceId() {
return provinceId;
}
public void setProvinceId(Long provinceId) {
this.provinceId = provinceId;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
package org.spring.springboot.dao;
import org.apache.ibatis.annotations.Param;
import org.spring.springboot.domain.City;
/**
* 城市 DAO 接口类
*
*/
public interface CityDao {
/**
* 根据城市名称,查询城市信息
*
* @param cityName 城市名
*/
City findByName(@Param("cityName") String cityName);
}
package org.spring.springboot.service;
import org.spring.springboot.domain.City;
/**
* 城市业务逻辑接口类
*
*/
public interface CityService {
/**
* 根据城市名称,查询城市信息
* @param cityName
*/
City findCityByName(String cityName);
}
package org.spring.springboot.service.impl;
import org.spring.springboot.dao.CityDao;
import org.spring.springboot.domain.City;
import org.spring.springboot.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 城市业务逻辑实现类
*
*/
@Service
public class CityServiceImpl implements CityService {
@Autowired
private CityDao cityDao;
public City findCityByName(String cityName) {
return cityDao.findByName(cityName);
}
}
package org.spring.springboot.controller;
import org.spring.springboot.domain.City;
import org.spring.springboot.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CityRestController {
@Autowired
private CityService cityService;
@RequestMapping(path="/api/city",method=RequestMethod.GET)
public City findCityByName(@RequestParam(value="cityName",required=true) String cityName){
return cityService.findCityByName(cityName);
}
@RequestMapping(path="/test/hotswapp")
public String testHotSwapping(){
return "测试热交换";
}
}
- 启动类
package org.spring.springboot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("org.spring.springboot.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- db
/*
Navicat MySQL Data Transfer
Source Server : 本地实例
Source Server Version : 50528
Source Host : localhost:3306
Source Database : springbootdb
Target Server Type : MYSQL
Target Server Version : 50528
File Encoding : 65001
Date: 2020-08-08 10:51:48
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for city
-- ----------------------------
DROP TABLE IF EXISTS `city`;
CREATE TABLE `city` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '城市编号',
`province_id` int(10) unsigned NOT NULL COMMENT '省份编号',
`city_name` varchar(25) DEFAULT NULL COMMENT '城市名称',
`description` varchar(25) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of city
-- ----------------------------
INSERT INTO `city` VALUES ('1', '1', '郭如飞的家', '郭如飞的家在武汉。');
问题总结
-
application.properties属性文件中文乱码问题,点击这里,亲测可用。