Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9dca7a2
Update README.md
JeffLi1993 Mar 1, 2019
f9ee57f
Update README.md
JeffLi1993 Mar 1, 2019
4deabd1
Update README.md
JeffLi1993 Mar 4, 2019
2583e9f
Update README.md
JeffLi1993 Mar 4, 2019
ad2faac
Update README.md
JeffLi1993 Mar 4, 2019
dd0f24c
Update application.properties
JeffLi1993 Mar 9, 2019
7e3e9fc
版本升级
Mar 19, 2019
bccf948
Spring Boot 集成 HBase
Mar 19, 2019
871ab7b
Update README.md
JeffLi1993 Mar 30, 2019
0beaae7
Update README.md
JeffLi1993 Mar 30, 2019
12b0dd6
Update README.md
JeffLi1993 Mar 30, 2019
c9c649f
Update README.md
JeffLi1993 Mar 31, 2019
82c407b
Update README.md
JeffLi1993 Mar 31, 2019
13a3ada
Update README.md
JeffLi1993 Apr 2, 2019
4d26dc3
Update README.md
JeffLi1993 Apr 3, 2019
d9496e6
Update README.md
JeffLi1993 Apr 3, 2019
ea8b763
优化依赖
Apr 10, 2019
e62ebc3
replace parameterMap with parameterType
Apr 10, 2019
7b80306
replace parameterMap with parameterType
Apr 10, 2019
cd6fa32
完善SpringBoot Hello World 单元测试
Apr 10, 2019
b71926b
Merge pull request #73 from strongant/master
JeffLi1993 Apr 11, 2019
a590fe4
Merge pull request #72 from developlee/master
JeffLi1993 Apr 11, 2019
95c76fa
WebFlux REST API 全局异常处理 Error Handling
Apr 11, 2019
5b902de
完善章节3单元测试
Apr 11, 2019
9bd8c91
Merge pull request #75 from strongant/master
JeffLi1993 Apr 13, 2019
6473f89
Update README.md
JeffLi1993 Apr 14, 2019
b107d49
完善章节4单元测试
Apr 15, 2019
5de6bb8
Merge pull request #76 from strongant/master
JeffLi1993 Apr 15, 2019
cbe0e43
Update README.md
JeffLi1993 Apr 15, 2019
a759a8f
Update README.md
JeffLi1993 Apr 16, 2019
d7a6496
CityHandler.deleteCity方法BUG修复
YuchangLi Apr 17, 2019
7b0b5f0
Update README.md
JeffLi1993 Apr 19, 2019
f3af92e
Merge pull request #78 from YuchangLi/master
JeffLi1993 Apr 19, 2019
fe2e348
Update README.md
JeffLi1993 Apr 20, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion chapter-4-spring-boot-validating-form-input/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

<!-- 模板引擎 Thymeleaf 依赖 -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
package spring.boot.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import spring.boot.core.domain.User;
import spring.boot.core.domain.UserRepository;

@SpringBootApplication
public class ValidatingFormInputApplication {
public class ValidatingFormInputApplication implements CommandLineRunner {

public static void main(String[] args) {
SpringApplication.run(ValidatingFormInputApplication.class, args);
}

private Logger LOG = LoggerFactory.getLogger(ValidatingFormInputApplication.class);

@Autowired
private UserRepository userRepository;

public static void main(String[] args) {
SpringApplication.run(ValidatingFormInputApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
User user1 = new User("Sergey", 24, "1994-01-01");
User user2 = new User("Ivan", 26, "1994-01-01");
User user3 = new User("Adam", 31, "1994-01-01");
LOG.info("Inserting data in DB.");
userRepository.save(user1);
userRepository.save(user2);
userRepository.save(user3);
LOG.info("User count in DB: {}", userRepository.count());
LOG.info("User with ID 1: {}", userRepository.findById(1L));
LOG.info("Deleting user with ID 2L form DB.");
userRepository.deleteById(2L);
LOG.info("User count in DB: {}", userRepository.count());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ public void setBirthday(String birthday) {
this.birthday = birthday;
}


public User(String name, Integer age, String birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}

public User() {}

@Override
public String toString() {
return "User{" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public String putUser(ModelMap map,
/**
* 处理 "/users/{id}" 的 GET 请求,用来删除 User 信息
*/
@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
public String deleteUser(@PathVariable Long id) {

userService.delete(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,15 @@
## 开启 H2 数据库
spring.h2.console.enabled=true

## 配置 H2 数据库连接信息
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=



## 是否显示 SQL 语句
spring.jpa.show-sql=true
spring.jpa.show-sql=true
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package spring.boot.core.web;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import spring.boot.core.ValidatingFormInputApplication;
import spring.boot.core.domain.User;
import spring.boot.core.service.UserService;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.junit.Assert.assertEquals;
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.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ValidatingFormInputApplication.class)
@AutoConfigureMockMvc
@TestPropertySource(locations = "classpath:application.properties")
public class UserControllerTest {


@Autowired
private MockMvc mockMvc;

@Autowired
private UserService userService;

@Autowired
private ObjectMapper objectMapper;

@Test
public void getUserList() throws Exception {
mockMvc.perform(get("/users"))
.andExpect(view().name("userList"))
.andExpect(status().isOk())
.andDo(print());
}

private User createUser() {
User user = new User();
user.setName("测试用户");
user.setAge(100);
user.setBirthday("1994-01-01");
return userService.insertByUser(user);
}

@Test
public void createUserForm() throws Exception {

mockMvc.perform(get("/users/create"))
.andDo(print())
.andExpect(view().name("userForm"))
.andExpect(request().attribute("action", "create"))
.andDo(print())
.andReturn();
}

@Test
public void postUser() throws Exception {
User user = createUser();
assertNotNull(user);

MultiValueMap parameters = new LinkedMultiValueMap<String, String>();
Map<String, String> maps = objectMapper.convertValue(user, new TypeReference<Map<String, String>>() {
});
parameters.setAll(maps);

mockMvc.perform(post("/users/create").params(parameters))
.andDo(print())
.andExpect(status().is(HttpServletResponse.SC_FOUND))
.andDo(print())
.andExpect(view().name("redirect:/users/"))
.andDo(print())
.andReturn();
}

@Test
public void getUser() throws Exception {

MvcResult result= mockMvc.perform(get("/users/update/{id}/", 1))
.andExpect(status().isOk())
.andExpect(view().name("userForm"))
.andExpect(MockMvcResultMatchers.model().attributeExists("action"))
.andExpect(model().attribute("user", hasProperty("id", is(1L))))
.andExpect(model().attribute("user", hasProperty("name", is("Sergey"))))
.andExpect(model().attribute("user", hasProperty("age", is(24))))
.andExpect(model().attribute("user", hasProperty("birthday", is("1994-01-01"))))
.andReturn();


MockHttpServletResponse mockResponse=result.getResponse();
assertThat(mockResponse.getContentType()).isEqualTo("text/html;charset=UTF-8");

Collection<String> responseHeaders = mockResponse.getHeaderNames();
assertNotNull(responseHeaders);
assertEquals(2, responseHeaders.size());
assertEquals("Check for Content-Type header", "Accept-Language", responseHeaders.iterator().next());
String responseAsString=mockResponse.getContentAsString();
assertTrue(responseAsString.contains("用户管理"));
}

@Test
public void putUser() throws Exception {
User user = createUser();
assertNotNull(user);

MultiValueMap parameters = new LinkedMultiValueMap<String, String>();
Map<String, String> maps = objectMapper.convertValue(user, new TypeReference<Map<String, String>>() {
});
parameters.setAll(maps);

mockMvc.perform(post("/users/update").params(parameters))
.andDo(print())
.andExpect(status().is(HttpServletResponse.SC_FOUND))
.andDo(print())
.andExpect(view().name("redirect:/users/"))
.andDo(print())
.andReturn();
}

@Test
public void deleteUser() throws Exception {
mockMvc.perform( MockMvcRequestBuilders.delete("/users/delete/{id}", 1L) )
.andDo(print())
.andExpect(status().is(HttpServletResponse.SC_FOUND))
.andExpect(view().name("redirect:/users/"));
}

public static byte[] convertObjectToJsonBytes(Object object) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper.writeValueAsBytes(object);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## 开启 H2 数据库
spring.h2.console.enabled=true

## 配置 H2 数据库连接信息
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=


## 是否显示 SQL 语句
spring.jpa.show-sql=true
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* contentDiv */
.contentDiv {padding:20px 60px;}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<script type="text/javascript" th:src="@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}"></script>
<link th:href="@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}" rel="stylesheet"/>
<link th:href="@{/css/default.css}" rel="stylesheet"/>
<link rel="icon" th:href="@{/images/favicon.ico}" type="image/x-icon"/>
<meta charset="UTF-8"/>
<title>用户管理</title>
</head>

<body>
<div class="contentDiv">

<h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>

<legend>
<strong>用户管理</strong>
</legend>

<form th:action="@{/users/{action}(action=${action})}" method="post" class="form-horizontal">

<input type="hidden" name="id" th:value="${user.id}"/>

<div class="form-group">
<label for="user_name" class="col-sm-2 control-label">名称:</label>
<div class="col-xs-4">
<input type="text" class="form-control" id="user_name" name="name" th:value="${user.name}" th:field="*{user.name}" />
</div>
<label class="col-sm-2 control-label text-danger" th:if="${#fields.hasErrors('user.name')}" th:errors="*{user.name}">姓名有误!</label>
</div>

<div class="form-group">
<label for="user_age" class="col-sm-2 control-label">年龄:</label>
<div class="col-xs-4">
<input type="text" class="form-control" id="user_age" name="age" th:value="${user.age}" th:field="*{user.age}" />
</div>
<label class="col-sm-2 control-label text-danger" th:if="${#fields.hasErrors('user.age')}" th:errors="*{user.age}">年龄有误!</label>
</div>

<div class="form-group">
<label for="user_birthday" class="col-sm-2 control-label">出生日期:</label>
<div class="col-xs-4">
<input type="date" class="form-control" id="user_birthday" name="birthday" th:value="${user.birthday}" th:field="*{user.birthday}"/>
</div>
<label class="col-sm-2 control-label text-danger" th:if="${#fields.hasErrors('user.birthday')}" th:errors="*{user.birthday}">生日有误!</label>
</div>

<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input class="btn btn-primary" type="submit" value="提交"/>&nbsp;&nbsp;
<input class="btn" type="button" value="返回" onclick="history.back()"/>
</div>
</div>
</form>
</div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<script type="text/javascript" th:src="@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}"></script>
<link th:href="@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}" rel="stylesheet"/>
<link th:href="@{/css/default.css}" rel="stylesheet"/>
<link rel="icon" th:href="@{/images/favicon.ico}" type="image/x-icon"/>
<meta charset="UTF-8"/>
<title>用户列表</title>
</head>

<body>

<div class="contentDiv">

<h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>

<table class="table table-hover table-condensed">
<legend>
<strong>用户列表</strong>
</legend>
<thead>
<tr>
<th>用户编号</th>
<th>名称</th>
<th>年龄</th>
<th>出生时间</th>
<th>管理</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${userList}">
<th scope="row" th:text="${user.id}"></th>
<td><a th:href="@{/users/update/{userId}(userId=${user.id})}" th:text="${user.name}"></a></td>
<td th:text="${user.age}"></td>
<td th:text="${user.birthday}"></td>
<td><a class="btn btn-danger" th:href="@{/users/delete/{userId}(userId=${user.id})}">删除</a></td>
</tr>
</tbody>
</table>

<div><a class="btn btn-primary" href="/users/create" role="button">创建用户</a></div>
</div>

</body>
</html>