Exception处理改进,使用Clock

This commit is contained in:
calvin.xiao
2015-11-11 00:51:58 +08:00
parent d66a0b2716
commit 16ca97b9cb
17 changed files with 177 additions and 118 deletions
+12
View File
@@ -22,6 +22,7 @@
<orika.version>1.4.6</orika.version>
<commons-codec.version>1.10</commons-codec.version>
<assertj.version>2.2.0</assertj.version>
<h2.version>1.3.176</h2.version>
<java.version>1.7</java.version>
</properties>
@@ -124,6 +125,17 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>3.1</version>
<configuration>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:file:~/.h2/bootapi;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1;</url>
<user>sa</user>
<password></password>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,15 +1,18 @@
package org.springside.examples.bootapi.api;
import java.util.Collections;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springside.examples.bootapi.api.support.RestException;
import org.springside.examples.bootapi.service.AccountService;
import org.springside.examples.bootapi.service.ServiceException;
import org.springside.examples.bootapi.service.exception.ErrorCode;
import org.springside.modules.web.MediaTypes;
// Spring Restful MVC Controller的标识, 直接输出内容,不调用template引擎.
@@ -21,14 +24,16 @@ public class AccountEndPoint {
@Autowired
private AccountService accountServcie;
@RequestMapping(value = "/api/accounts/login", produces = MediaTypes.TEXT_PLAIN_UTF_8)
public String login(@RequestParam("email") String email, @RequestParam("password") String password) {
@RequestMapping(value = "/api/accounts/login", produces = MediaTypes.JSON_UTF_8)
public Map<String, String> login(@RequestParam("email") String email, @RequestParam("password") String password) {
if (StringUtils.isEmpty(email) || StringUtils.isEmpty(password)) {
throw new RestException("User or password empty", HttpStatus.BAD_REQUEST);
throw new ServiceException("User or password empty", ErrorCode.BAD_REQUEST);
}
return accountServcie.login(email, password);
String token = accountServcie.login(email, password);
return Collections.singletonMap("token", token);
}
@RequestMapping(value = "/api/accounts/logout")
@@ -41,7 +46,7 @@ public class AccountEndPoint {
@RequestParam("password") String password) {
if (StringUtils.isEmpty(email) || StringUtils.isEmpty(name) || StringUtils.isEmpty(password)) {
throw new RestException("User or name or password empty", HttpStatus.BAD_REQUEST);
throw new ServiceException("User or name or password empty", ErrorCode.BAD_REQUEST);
}
accountServcie.register(email, name, password);
@@ -18,6 +18,8 @@ import org.springside.examples.bootapi.dto.BookDto;
import org.springside.examples.bootapi.service.AccountService;
import org.springside.examples.bootapi.service.BookAdminService;
import org.springside.examples.bootapi.service.BookBorrowService;
import org.springside.examples.bootapi.service.ServiceException;
import org.springside.examples.bootapi.service.exception.ErrorCode;
import org.springside.modules.mapper.BeanMapper;
import org.springside.modules.web.MediaTypes;
@@ -53,7 +55,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books", method = RequestMethod.POST, consumes = MediaTypes.JSON_UTF_8)
public void createBook(@RequestBody BookDto bookDto,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
// 使用Header中的Token,查找登录用户
Account currentUser = accountService.getLoginUser(token);
@@ -67,6 +69,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/modify", method = RequestMethod.POST, consumes = MediaTypes.JSON_UTF_8)
public void modifyBook(@RequestBody BookDto bookDto,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
Book book = BeanMapper.map(bookDto, Book.class);
adminService.modifyBook(book, currentUser.id);
@@ -74,6 +77,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/delete")
public void deleteBook(@PathVariable("id") Long id, @RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
adminService.deleteBook(id, currentUser.id);
}
@@ -81,6 +85,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/request")
public void applyBorrowRequest(@PathVariable("id") Long id,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
borrowService.applyBorrowRequest(id, currentUser);
}
@@ -88,6 +93,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/cancel")
public void cancelBorrowRequest(@PathVariable("id") Long id,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
borrowService.cancelBorrowRequest(id, currentUser);
}
@@ -95,6 +101,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/confirm")
public void markBookBorrowed(@PathVariable("id") Long id,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
borrowService.markBookBorrowed(id, currentUser);
}
@@ -102,6 +109,7 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/reject")
public void rejectBorrowRequest(@PathVariable("id") Long id,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
borrowService.rejectBorrowRequest(id, currentUser);
}
@@ -109,12 +117,14 @@ public class BookEndpoint {
@RequestMapping(value = "/api/books/{id}/return")
public void markBookReturned(@PathVariable("id") Long id,
@RequestParam(value = "token", required = false) String token) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
borrowService.markBookReturned(id, currentUser);
}
@RequestMapping(value = "/api/mybook", produces = MediaTypes.JSON_UTF_8)
public List<BookDto> listMyBook(@RequestParam(value = "token", required = false) String token, Pageable pageable) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
List<Book> books = adminService.listMyBook(currentUser.id, pageable);
return BeanMapper.mapList(books, BookDto.class);
@@ -123,8 +133,15 @@ public class BookEndpoint {
@RequestMapping(value = "/api/myborrowedbook", produces = MediaTypes.JSON_UTF_8)
public List<BookDto> listMyBorrowedBook(@RequestParam(value = "token", required = false) String token,
Pageable pageable) {
checkToken(token);
Account currentUser = accountService.getLoginUser(token);
List<Book> books = borrowService.listMyBorrowedBook(currentUser.id, pageable);
return BeanMapper.mapList(books, BookDto.class);
}
private void checkToken(String token) {
if (token == null) {
throw new ServiceException("No token in request", ErrorCode.NO_TOKEN);
}
}
}
@@ -1,15 +0,0 @@
package org.springside.examples.bootapi.api.support;
import org.springframework.http.HttpStatus;
public class RestException extends RuntimeException {
private static final long serialVersionUID = -8634700792767837033L;
public HttpStatus status;
public RestException(String message, HttpStatus status) {
super(message);
this.status = status;
}
}
@@ -1,22 +0,0 @@
package org.springside.examples.bootapi.api.support;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springside.modules.web.MediaTypes;
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { RestException.class })
public final ResponseEntity<?> handleException(RestException ex, WebRequest request) {
logger.error(ex.getMessage(), ex);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(MediaTypes.TEXT_PLAIN_UTF_8));
return new ResponseEntity<Object>(ex.getMessage(), headers, ex.status);
}
}
@@ -0,0 +1,42 @@
package org.springside.examples.bootapi.api.support;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springside.examples.bootapi.service.ServiceException;
import org.springside.modules.web.MediaTypes;
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { ServiceException.class })
public final ResponseEntity<?> handleException(ServiceException ex, HttpServletRequest request) {
logger.error(ex.getMessage() + ", request from " + request.getRemoteAddr(), ex);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(MediaTypes.JSON_UTF_8));
ErrorResult result = new ErrorResult(ex.code.code, ex.getMessage());
return new ResponseEntity<Object>(result, headers, HttpStatus.valueOf(ex.code.httpStatus));
}
public static class ErrorResult {
public int code;
public String message;
public ErrorResult() {
}
public ErrorResult(int code, String message) {
this.code = code;
this.message = message;
}
}
}
@@ -32,10 +32,10 @@ public class Message {
}
public Message(Account receiver, String message) {
public Message(Account receiver, String message, Date receiveDate) {
this.receiver = receiver;
this.message = message;
this.receiveDate = new Date();
this.receiveDate = receiveDate;
}
@Override
@@ -9,12 +9,11 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springside.examples.bootapi.api.support.RestException;
import org.springside.examples.bootapi.domain.Account;
import org.springside.examples.bootapi.repository.AccountDao;
import org.springside.examples.bootapi.service.exception.ErrorCode;
import org.springside.modules.utils.Digests;
import org.springside.modules.utils.Encodes;
import org.springside.modules.utils.Ids;
@@ -53,11 +52,11 @@ public class AccountService {
Account account = accountDao.findByEmail(email);
if (account == null) {
throw new RestException("User not exist", HttpStatus.UNAUTHORIZED);
throw new ServiceException("User not exist", ErrorCode.UNAUTHORIZED);
}
if (!account.hashPassword.equals(hashPassword(password))) {
throw new RestException("Password wrong", HttpStatus.UNAUTHORIZED);
throw new ServiceException("Password wrong", ErrorCode.UNAUTHORIZED);
}
String token = Ids.uuid2();
@@ -78,15 +77,10 @@ public class AccountService {
public Account getLoginUser(String token) {
if (token == null) {
logger.error("no token");
throw new RestException("User doesn't login", HttpStatus.UNAUTHORIZED);
}
Account account = loginUsers.getIfPresent(token);
if (account == null) {
throw new RestException("User doesn't login", HttpStatus.UNAUTHORIZED);
throw new ServiceException("User doesn't login", ErrorCode.UNAUTHORIZED);
}
return account;
@@ -1,19 +1,18 @@
package org.springside.examples.bootapi.service;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springside.examples.bootapi.api.support.RestException;
import org.springside.examples.bootapi.domain.Account;
import org.springside.examples.bootapi.domain.Book;
import org.springside.examples.bootapi.repository.BookDao;
import org.springside.examples.bootapi.service.exception.ErrorCode;
import org.springside.modules.utils.Clock;
// Spring Bean的标识.
@Service
@@ -24,6 +23,9 @@ public class BookAdminService {
@Autowired
private BookDao bookDao;
// 可注入的Clock,方便测试时控制日期
protected Clock clock = Clock.DEFAULT;
@Transactional(readOnly = true)
public Iterable<Book> findAll(Pageable pageable) {
return bookDao.findAll(pageable);
@@ -44,7 +46,7 @@ public class BookAdminService {
book.owner = owner;
book.status = Book.STATUS_IDLE;
book.onboardDate = new Date();
book.onboardDate = clock.getCurrentDate();
bookDao.save(book);
}
@@ -52,7 +54,7 @@ public class BookAdminService {
@Transactional
public void modifyBook(Book book, Long currentAccountId) {
if (!currentAccountId.equals(book.owner.id)) {
throw new RestException("User can't modify others book", HttpStatus.FORBIDDEN);
throw new ServiceException("User can't modify others book", ErrorCode.BOOK_OWNERSHIP_WRONG);
}
Book orginalBook = bookDao.findOne(book.id);
@@ -66,7 +68,7 @@ public class BookAdminService {
Book book = bookDao.findOne(id);
if (!currentAccountId.equals(book.owner.id)) {
throw new RestException("User can't delete others book", HttpStatus.FORBIDDEN);
throw new ServiceException("User can't delete others book", ErrorCode.BOOK_OWNERSHIP_WRONG);
}
bookDao.delete(id);
@@ -1,21 +1,20 @@
package org.springside.examples.bootapi.service;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springside.examples.bootapi.api.support.RestException;
import org.springside.examples.bootapi.domain.Account;
import org.springside.examples.bootapi.domain.Book;
import org.springside.examples.bootapi.domain.Message;
import org.springside.examples.bootapi.repository.BookDao;
import org.springside.examples.bootapi.repository.MessageDao;
import org.springside.examples.bootapi.service.exception.ErrorCode;
import org.springside.modules.utils.Clock;
// Spring Bean的标识.
@Service
@@ -29,6 +28,9 @@ public class BookBorrowService {
@Autowired
protected MessageDao messageDao;
// 可注入的Clock,方便测试时控制日期
protected Clock clock = Clock.DEFAULT;
@Transactional
public void applyBorrowRequest(Long id, Account borrower) {
Book book = bookDao.findOne(id);
@@ -36,12 +38,13 @@ public class BookBorrowService {
if (!book.status.equals(Book.STATUS_IDLE)) {
logger.error("User request the book not idle, user id:" + borrower.id + ",book id:" + id + ",status:"
+ book.status);
throw new RestException("The book is not idle", HttpStatus.BAD_REQUEST);
throw new ServiceException("The book is not idle", ErrorCode.BOOK_STATUS_WRONG);
}
if (borrower.id.equals(book.owner.id)) {
logger.error("User borrow the book himself, user id:" + borrower.id + ",book id:" + id);
throw new RestException("User shouldn't borrower the book which is himeself", HttpStatus.BAD_REQUEST);
throw new ServiceException("User shouldn't borrower the book which is himeself",
ErrorCode.BOOK_OWNERSHIP_WRONG);
}
book.status = Book.STATUS_REQUEST;
@@ -49,7 +52,7 @@ public class BookBorrowService {
bookDao.save(book);
Message message = new Message(book.owner,
String.format("Apply book <%s> request by %s", book.title, borrower.name));
String.format("Apply book <%s> request by %s", book.title, borrower.name), clock.getCurrentDate());
messageDao.save(message);
}
@@ -61,13 +64,13 @@ public class BookBorrowService {
if (!book.status.equals(Book.STATUS_REQUEST)) {
logger.error("User cancel the book not reqesting, user id:" + borrower.id + ",book id:" + id + ",status:"
+ book.status);
throw new RestException("The book is not requesting", HttpStatus.BAD_REQUEST);
throw new ServiceException("The book is not requesting", ErrorCode.BOOK_STATUS_WRONG);
}
if (!borrower.id.equals(book.borrower.id)) {
logger.error("User cancel the book not request by him, user id:" + borrower.id + ",book id:" + id
+ ",borrower id" + book.borrower.id);
throw new RestException("User can't cancel other ones request", HttpStatus.FORBIDDEN);
throw new ServiceException("User can't cancel other ones request", ErrorCode.BOOK_OWNERSHIP_WRONG);
}
book.status = Book.STATUS_IDLE;
@@ -75,7 +78,7 @@ public class BookBorrowService {
bookDao.save(book);
Message message = new Message(book.owner,
String.format("Cancel book <%s> request by %s", book.title, borrower.name));
String.format("Cancel book <%s> request by %s", book.title, borrower.name), clock.getCurrentDate());
messageDao.save(message);
}
@@ -87,21 +90,21 @@ public class BookBorrowService {
if (!book.status.equals(Book.STATUS_REQUEST)) {
logger.error("User confirm the book not reqesting, user id:" + owner.id + ",book id:" + id + ",status:"
+ book.status);
throw new RestException("The book is not requesting", HttpStatus.BAD_REQUEST);
throw new ServiceException("The book is not requesting", ErrorCode.BOOK_STATUS_WRONG);
}
if (!owner.id.equals(book.owner.id)) {
logger.error("User confirm the book not himself, user id:" + owner.id + ",book id:" + id + ",owner id"
+ book.owner.id);
throw new RestException("User can't cofirm others book", HttpStatus.FORBIDDEN);
throw new ServiceException("User can't cofirm others book", ErrorCode.BOOK_OWNERSHIP_WRONG);
}
book.status = Book.STATUS_OUT;
book.borrowDate = new Date();
book.borrowDate = clock.getCurrentDate();
bookDao.save(book);
Message message = new Message(book.borrower,
String.format("Confirm book <%s> request by %s", book.title, owner.name));
String.format("Confirm book <%s> request by %s", book.title, owner.name), clock.getCurrentDate());
messageDao.save(message);
}
@@ -112,14 +115,14 @@ public class BookBorrowService {
if (!book.status.equals(Book.STATUS_REQUEST)) {
logger.error("User reject the book not reqesting, user id:" + owner.id + ",book id:" + id + ",status:"
+ book.status);
throw new RestException("The book is not requesting", HttpStatus.BAD_REQUEST);
throw new ServiceException("The book is not requesting", ErrorCode.BOOK_STATUS_WRONG);
}
if (!owner.id.equals(book.owner.id)) {
logger.error("User reject the book not himself, user id:" + owner.id + ",book id:" + id + ",owener id"
+ book.owner.id);
throw new RestException("User can't reject others book", HttpStatus.FORBIDDEN);
throw new ServiceException("User can't reject others book", ErrorCode.BOOK_OWNERSHIP_WRONG);
}
book.status = Book.STATUS_IDLE;
@@ -128,7 +131,7 @@ public class BookBorrowService {
bookDao.save(book);
Message message = new Message(book.borrower,
String.format("Reject book <%s> request by %s", book.title, owner.name));
String.format("Reject book <%s> request by %s", book.title, owner.name), clock.getCurrentDate());
messageDao.save(message);
}
@@ -139,13 +142,13 @@ public class BookBorrowService {
if (!book.status.equals(Book.STATUS_OUT)) {
logger.error(
"User return the book not out, user id:" + owner.id + ",book id:" + id + ",status:" + book.status);
throw new RestException("The book is not borrowing", HttpStatus.BAD_REQUEST);
throw new ServiceException("The book is not borrowing", ErrorCode.BOOK_STATUS_WRONG);
}
if (!owner.id.equals(book.owner.id)) {
logger.error("User return the book not himself, user id:" + owner.id + ",book id:" + id + ",owner id"
+ book.owner.id);
throw new RestException("User can't make others book returned", HttpStatus.FORBIDDEN);
throw new ServiceException("User can't make others book returned", ErrorCode.BOOK_OWNERSHIP_WRONG);
}
book.status = Book.STATUS_IDLE;
@@ -154,7 +157,7 @@ public class BookBorrowService {
bookDao.save(book);
Message message = new Message(book.borrower,
String.format("Mark book <%s> returned by %s", book.title, owner.name));
String.format("Mark book <%s> returned by %s", book.title, owner.name), clock.getCurrentDate());
messageDao.save(message);
}
@@ -0,0 +1,15 @@
package org.springside.examples.bootapi.service;
import org.springside.examples.bootapi.service.exception.ErrorCode;
public class ServiceException extends RuntimeException {
private static final long serialVersionUID = -8634700792767837033L;
public ErrorCode code;
public ServiceException(String message, ErrorCode code) {
super(message);
this.code = code;
}
}
@@ -0,0 +1,17 @@
package org.springside.examples.bootapi.service.exception;
public enum ErrorCode {
BAD_REQUEST(1000, 400), UNAUTHORIZED(1001, 401), FORBIDDEN(1002, 403),
BOOK_STATUS_WRONG(1100, 400), BOOK_OWNERSHIP_WRONG(1101, 403), NO_TOKEN(1102, 401);
public int code;
public int httpStatus;
ErrorCode(int code, int httpStatus) {
this.code = code;
this.httpStatus = httpStatus;
}
}
@@ -8,6 +8,7 @@ spring.datasource.password=
#disable automatic initialize for embedded H2
spring.jpa.hibernate.ddl-auto=none
spring.datasource.initialize=false
flyway.enabled=true
#connection pool settings
spring.datasource.initial-size=10
@@ -9,6 +9,8 @@ app.loginTimeoutSecs=600
spring.datasource.sqlScriptEncoding=UTF-8
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.showsql=false
spring.datasource.initialize=true
flyway.enabled=false
# other settings
spring.main.show-banner=false
@@ -32,9 +32,12 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;
import org.springside.examples.bootapi.BootApiApplication;
import org.springside.examples.bootapi.api.support.ServiceExceptionHandler.ErrorResult;
import org.springside.examples.bootapi.domain.Book;
import org.springside.examples.bootapi.dto.BookDto;
import org.springside.examples.bootapi.repository.BookDao;
import org.springside.examples.bootapi.service.exception.ErrorCode;
import org.springside.modules.mapper.JsonMapper;
import org.springside.modules.test.data.RandomData;
import com.google.common.collect.Maps;
@@ -53,6 +56,8 @@ public class BookEndpointTest {
private BookDao bookDao;
private RestTemplate restTemplate;
private JsonMapper jsonMapper = new JsonMapper();
private String resourceUrl;
private String loginUrl;
private String logoutUrl;
@@ -101,6 +106,8 @@ public class BookEndpointTest {
// 未设置token
ResponseEntity<String> response = restTemplate.getForEntity(resourceUrl + "/{id}/request", String.class, 1L);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
ErrorResult errorResult = jsonMapper.fromJson(response.getBody(), ErrorResult.class);
assertThat(errorResult.code).isEqualTo(ErrorCode.NO_TOKEN.code);
Book book = bookDao.findOne(1L);
assertThat(book.borrower).isNull();
@@ -108,6 +115,8 @@ public class BookEndpointTest {
// 设置错误token
response = restTemplate.getForEntity(resourceUrl + "/{id}/request?token={token}", String.class, 1L, "abc");
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
errorResult = jsonMapper.fromJson(response.getBody(), ErrorResult.class);
assertThat(errorResult.code).isEqualTo(ErrorCode.UNAUTHORIZED.code);
book = bookDao.findOne(1L);
assertThat(book.borrower).isNull();
@@ -116,7 +125,9 @@ public class BookEndpointTest {
String token = login("calvin.xiao@vipshop.com");
response = restTemplate.getForEntity(resourceUrl + "/{id}/request?token={token}", String.class, 1L, token);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
errorResult = jsonMapper.fromJson(response.getBody(), ErrorResult.class);
assertThat(errorResult.code).isEqualTo(ErrorCode.BOOK_OWNERSHIP_WRONG.code);
book = bookDao.findOne(1L);
assertThat(book.borrower).isNull();
@@ -131,6 +142,8 @@ public class BookEndpointTest {
response = restTemplate.getForEntity(resourceUrl + "/{id}/request?token={token}", String.class, 3L, token);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
errorResult = jsonMapper.fromJson(response.getBody(), ErrorResult.class);
assertThat(errorResult.code).isEqualTo(ErrorCode.BOOK_STATUS_WRONG.code);
// 回退操作
response = restTemplate.getForEntity(resourceUrl + "/{id}/cancel?token={token}", String.class, 3L, token);
@@ -145,8 +158,8 @@ public class BookEndpointTest {
// 发起请求
String token = login("david02.wang@vipshop.com");
ResponseEntity response = restTemplate.getForEntity(resourceUrl + "/{id}/request?token={token}", String.class,
1L, token);
ResponseEntity<String> response = restTemplate.getForEntity(resourceUrl + "/{id}/request?token={token}",
String.class, 1L, token);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
logout(token);
@@ -167,10 +180,10 @@ public class BookEndpointTest {
map.put("email", user);
map.put("password", "springside");
ResponseEntity<String> response = restTemplate.getForEntity(loginUrl + "?email={email}&password={password}",
String.class, map);
ResponseEntity<Map> response = restTemplate.getForEntity(loginUrl + "?email={email}&password={password}",
Map.class, map);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
return response.getBody();
return (String) response.getBody().get("token");
}
public void logout(String token) {
-12
View File
@@ -34,24 +34,12 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
/**
* 简单封装Jackson,实现JSON String<->Java Object的Mapper.
@@ -64,9 +63,7 @@ public class JsonMapper {
}
/**
* Object可以是POJO,也可以是Collection或数组。
* 如果对象为Null, 返回"null".
* 如果集合为空集合, 返回"[]".
* Object可以是POJO,也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]".
*/
public String toJson(Object object) {
@@ -81,8 +78,7 @@ public class JsonMapper {
/**
* 反序列化POJO或简单Collection如List<String>.
*
* 如果JSON字符串为Null或"null"字符串, 返回Null.
* 如果JSON字符串为"[]", 返回空集合.
* 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
*
* 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
*
@@ -154,24 +150,13 @@ public class JsonMapper {
}
/**
* 設定是否使用Enum的toString函數來讀寫Enum,
* 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
* 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
* 設定是否使用Enum的toString函數來讀寫Enum, 為False時時使用Enum的name()函數來讀寫Enum, 默認為False. 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
*/
public void enableEnumUseToString() {
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
}
/**
* 支持使用Jaxb的Annotation,使得POJO上的annotation不用与Jackson耦合。
* 默认会先查找jaxb的annotation,如果找不到再找jackson的。
*/
public void enableJaxbAnnotation() {
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
}
/**
* 取出Mapper做进一步的设置或使用其他序列化API.
*/