-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement rest API for Member, add swagger, flyway db migration.
- Loading branch information
hoangtle
committed
Nov 3, 2016
1 parent
c766e02
commit 848fea0
Showing
13 changed files
with
408 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
1|Messi||Lionel|[email protected]|0939481929|1987-01-01 | ||
2|Ronaldo||Cristiano|[email protected]|0939481929|1985-01-01 | ||
3|Xavier||Creus|[email protected]|0939481929|1980-01-01 | ||
4|Iniesta||Andres|[email protected]|0939481929|1984-01-01 | ||
5|Ibrahimovic||Zlatan|[email protected]|0939481929|1981-01-01 | ||
6|Falcao||Radamel|[email protected]|0939481929|1986-01-01 | ||
7|Persie||Robin|[email protected]|0939481929|1983-01-01 | ||
8|Pirlo||Andrea|[email protected]|0939481929|1987-01-01 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,23 @@ | ||
package com.trhoanglee.expense; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import java.io.IOException; | ||
|
||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.boot.autoconfigure.domain.EntityScan; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.context.annotation.ComponentScan; | ||
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters; | ||
|
||
/** | ||
* @author hoangtle | ||
*/ | ||
@ComponentScan | ||
@EnableAutoConfiguration | ||
@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class}) | ||
@SpringBootApplication | ||
public class Application { | ||
private static final Logger LOG = LoggerFactory.getLogger(Application.class.getCanonicalName()); | ||
public static void main(String... args) { | ||
ApplicationContext appContext = SpringApplication.run(Application.class, args); | ||
|
||
MemberService memberService = appContext.getBean(MemberService.class); | ||
LOG.info(memberService.ping()); | ||
SpringApplication.exit(appContext); | ||
} | ||
public static void main(String... args) throws IOException { | ||
ApplicationContext appContext = SpringApplication.run(Application.class, args); | ||
MemberService memberService = appContext.getBean(MemberService.class); | ||
String membersFilePath = (args.length > 0)? args[0] : "etc/members.txt"; | ||
memberService.loadMembersFromFile(membersFilePath); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,86 @@ | ||
package com.trhoanglee.expense; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.FileReader; | ||
import java.io.IOException; | ||
import java.util.Date; | ||
import java.util.List; | ||
|
||
import javax.validation.Valid; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.data.domain.PageRequest; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import com.trhoanglee.expense.domain.Member; | ||
import com.trhoanglee.expense.domain.Name; | ||
import com.trhoanglee.expense.repository.MemberRepository; | ||
|
||
/** | ||
* @author trhoanglee | ||
*/ | ||
@Service | ||
@Transactional(readOnly = true) | ||
public class MemberService { | ||
public String ping() { | ||
return "pong"; | ||
@Autowired | ||
private MemberRepository memberRepo; | ||
|
||
@Transactional | ||
public Member saveMember(@Valid Member member) { | ||
return memberRepo.save(member); | ||
} | ||
|
||
@Transactional | ||
public void deleteAllMembers() { | ||
memberRepo.deleteAllInBatch(); | ||
} | ||
|
||
public Member getMember(Long id) { | ||
return memberRepo.getOne(id); | ||
} | ||
|
||
public List<Member> search(String keyword, int page, int pageSize) { | ||
keyword = (keyword == null) ? "" : keyword; | ||
return memberRepo.searchMembers(keyword, new PageRequest(page, pageSize)); | ||
} | ||
|
||
@Transactional | ||
public void deleteMembers(String[] ids) { | ||
memberRepo.deleteMembers(ids); | ||
} | ||
|
||
@Transactional | ||
public long loadMembersFromFile(String filePath) throws IOException { | ||
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { | ||
return reader.lines() | ||
.map(this::parseMember) | ||
.map(this::saveMember) | ||
.count(); | ||
} | ||
} | ||
|
||
/** | ||
* memberLine format: id|firstName|middleName|lastName|email|mobile|dob dob | ||
* format: yyyy-MM-dd | ||
*/ | ||
private Member parseMember(String memberLine) { | ||
String[] items = memberLine.split("\\|"); | ||
if (items.length < 7) { | ||
throw new IllegalArgumentException(String.format("Invalid member-line format: %s", memberLine)); | ||
} | ||
|
||
Member member = new Member(); | ||
try { | ||
member.setId(Long.parseLong(items[0])); | ||
} catch (NumberFormatException ex) { | ||
throw new IllegalArgumentException(String.format("Invalid member-line format: %s", memberLine, ex)); | ||
} | ||
member.setName(new Name(items[1], items[2], items[3])); | ||
member.setEmail(items[4]); | ||
member.setMobile(items[5]); | ||
member.setDob(new Date(java.sql.Date.valueOf(items[6]).getTime())); | ||
return member; | ||
} | ||
|
||
} |
28 changes: 28 additions & 0 deletions
28
src/main/java/com/trhoanglee/expense/config/CommonConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.trhoanglee.expense.config; | ||
|
||
import org.springframework.context.MessageSource; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.support.ReloadableResourceBundleMessageSource; | ||
import org.springframework.context.support.ResourceBundleMessageSource; | ||
import org.springframework.validation.Validator; | ||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; | ||
|
||
|
||
@Configuration | ||
public class CommonConfig { | ||
@Bean | ||
public MessageSource messageSource() { | ||
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); | ||
messageSource.setBasenames("classpath:i18n/messages", "classpath:i18n/validation"); | ||
messageSource.setDefaultEncoding("UTF-8"); | ||
return messageSource; | ||
} | ||
|
||
@Bean | ||
public Validator validator() { | ||
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean(); | ||
factoryBean.setValidationMessageSource(messageSource()); | ||
return factoryBean; | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/com/trhoanglee/expense/config/SecurityConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.trhoanglee.expense.config; | ||
|
||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||
|
||
@Configuration | ||
public class SecurityConfig extends WebSecurityConfigurerAdapter { | ||
@Override | ||
protected void configure(HttpSecurity http) throws Exception { | ||
http.httpBasic().and() | ||
.csrf().disable() | ||
.authorizeRequests() | ||
.antMatchers("/api/**").permitAll() | ||
.anyRequest().permitAll(); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/main/java/com/trhoanglee/expense/config/SwaggerConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.trhoanglee.expense.config; | ||
|
||
import static springfox.documentation.builders.PathSelectors.regex; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.util.StopWatch; | ||
|
||
import springfox.documentation.spi.DocumentationType; | ||
import springfox.documentation.spring.web.plugins.Docket; | ||
import springfox.documentation.swagger2.annotations.EnableSwagger2; | ||
|
||
@Configuration | ||
@EnableSwagger2 | ||
public class SwaggerConfig { | ||
private final Logger logger = LoggerFactory.getLogger(SwaggerConfig.class); | ||
|
||
@Bean | ||
public Docket swaggerSpringfoxDocket() { | ||
logger.debug("Starting Swagger"); | ||
StopWatch watch = new StopWatch(); | ||
watch.start(); | ||
|
||
Docket docket = new Docket(DocumentationType.SWAGGER_2) | ||
.select() | ||
.paths(regex("/api/.*")) | ||
.build(); | ||
|
||
watch.stop(); | ||
logger.debug("Started Swagger in {} ms", watch.getTotalTimeMillis()); | ||
|
||
return docket; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/trhoanglee/expense/repository/ExpenseRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.trhoanglee.expense.repository; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import com.trhoanglee.expense.domain.Expense; | ||
|
||
public interface ExpenseRepository extends JpaRepository<Expense, Long>{ | ||
|
||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/com/trhoanglee/expense/util/CommonUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.trhoanglee.expense.util; | ||
|
||
import javax.ws.rs.BadRequestException; | ||
|
||
public class CommonUtils { | ||
public static Long parsePathVariableId(String id) { | ||
try { | ||
return Long.parseLong(id); | ||
} catch (NumberFormatException ex) { | ||
throw new BadRequestException(String.format("'%s' is not a valid id", id)); | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
src/main/java/com/trhoanglee/expense/web/controller/ExceptionController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.trhoanglee.expense.web.controller; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.validation.BindingResult; | ||
import org.springframework.validation.FieldError; | ||
import org.springframework.web.bind.MethodArgumentNotValidException; | ||
import org.springframework.web.bind.annotation.ControllerAdvice; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@ControllerAdvice | ||
@RestController | ||
public class ExceptionController { | ||
private static final Logger LOG = LoggerFactory.getLogger(ExceptionController.class.getCanonicalName()); | ||
|
||
|
||
@ExceptionHandler(MethodArgumentNotValidException.class) | ||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
public Map<String, String> handleValidationError(MethodArgumentNotValidException ex) { | ||
Map<String, String> fieldErrorMap = new HashMap<>(); | ||
|
||
BindingResult result = ex.getBindingResult(); | ||
List<FieldError> fieldErrors = result.getFieldErrors(); | ||
for (FieldError fieldError: fieldErrors) { | ||
fieldErrorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); | ||
} | ||
|
||
return fieldErrorMap; | ||
} | ||
|
||
@ExceptionHandler(Exception.class) | ||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) | ||
public String handleUnexpectedException(Exception ex) { | ||
LOG.error("Error during process request", ex); | ||
return ex.getMessage(); | ||
} | ||
} |
Oops, something went wrong.