[ ] (Java, Spring Boot, Gradle) |
. , , , .
( ), . Java . , - . , , , .
, , , . - , . Spring Boot, Spring Data, Gradle.
, . ( , ). , Spring.
, :
user-service
: (, , )lesson-service
: (, )result-service
: ( , )task-executor-service
: ( ) , - . , API .
gateway-service
.
:
, , RestTemplate
. , , Zuul. Spring Boot .
build.gradle :
plugins {
id 'java'
id 'war'
}
apply plugin: 'spring-boot'
springBoot {
mainClass 'gateway.App'
}
dependencies {
compile('org.springframework.cloud:spring-cloud-starter-zuul:1.2.0.RELEASE')
compile('org.springframework.boot:spring-boot-starter-web')
}
, App.java:
@SpringBootApplication
@EnableZuulProxy
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
ZuulProxy. , application.properties
:
zuul.routes.lesson-service.url=http://localhost:8081
zuul.routes.user-service.url=http://localhost:8082
zuul.routes.task-executor-service.url=http://localhost:8083
zuul.routes.result-service.url=http://localhost:8084
zuul.prefix=/services
, /services/lesson-service/...
http://localhost:8081/...
.. .
Zuul , .
, , . gateway-service/src/main/webapp/...
.
. :
. .
. MySQL
, user-service
, lesson-service
answer-service
. A task-executor-service
, . , .
, . . -.
, , . , , - .
, service-client
. , -, , - . - Entity
, , .
- Client:
abstract class Client {
private final RestTemplate rest;
private final String serviceFullPath;
private final static String GATEWAY_PATH = "http://localhost:8080/services";
Client(final String servicePath) {
this.rest = new RestTemplate(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
this.serviceFullPath = GATEWAY_PATH + servicePath;
}
protected T get(final String path, final Class type) {
return rest.getForObject(serviceFullPath + path, type);
}
protected T post(final String path, final E object, final Class type) {
return rest.postForObject(serviceFullPath + path, object, type);
}
}
GATEWAY_PATH
-, .
lesson-service
:
public class TaskClient extends Client {
private static final String SERVICE_PATH = "/lesson-service/task/";
public TaskClient() {
super(SERVICE_PATH);
}
public Task get(final Long id) {
return get(id.toString(), TaskResult.class).getData();
}
public List getList() {
return get("", TaskListResult.class).getData();
}
public List getListByLesson(final Long lessonId) {
return get("/getByLesson/" + lessonId, TaskListResult.class).getData();
}
public Task add(final TaskCreation taskCreation) {
return post( "/add", taskCreation, TaskResult.class).getData();
}
}
, Result
getData()
. json, -, , . Result
, T
:
@Data
public class Result {
public String message;
public T data;
public static Result success(final T data) {
return new Result<>(null, data);
}
public static Result error(final String message) {
return new Result<>(message, null);
}
public static Result run(final Supplier function ) {
final T result = function.get();
return Result.success(result);
}
}
getData()
, . @Data
lombok, .Result
, - ( ), - .
, , (compile project(':service-client')
dependencies) . result-service
:
@SpringBootApplication(scanBasePackages = "result")
@EnableJpaRepositories("result.repository")
@Configuration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Bean
public UserClient getUserClient() {
return new UserClient();
}
@Bean
public TaskClient getTaskClient() {
return new TaskClient();
}
@Bean
public ExecutorClient getTaskExecutor() {
return new ExecutorClient();
}
}
:
@RestController
@RequestMapping
public class ResultController {
@Autowired
private ResultService service;
@RequestMapping(value = "/submit", method = RequestMethod.POST)
public Result submit(@RequestBody final SubmitRequest submit){
return run(() -> service.submit(submit));
}
@RequestMapping(value = "/getByTask/{id}", method = RequestMethod.GET)
public Result> getByTask(@PathVariable final Long id) {
return run(() -> service.getByTask(id));
}
}
, Result
. :
@Service
@Transactional
public class ResultService {
@Autowired
private AnswerRepository answerRepository;
@Autowired
private TaskClient taskClient;
@Autowired
private ExecutorClient executorClient;
public TaskResult submit(final SubmitRequest submit) {
val task = taskClient.get(submit.getTaskId());
if (task == null)
throw new RuntimeException("Invalid task id");
val result = executorClient.submit(submit);
val answerEntity = new AnswerEntity();
answerEntity.setAnswer(submit.getCode());
answerEntity.setTaskId(task.getId());
answerEntity.setUserId(1L);
answerEntity.setCorrect(result.getStatus() == TaskResult.Status.SUCCESS);
answerRepository.save(answerEntity);
return result;
}
...
answerEntity.setUserId(1L)
, .
, . . .
, , .
, , , . , , .
, Redis
, hello-world . , , JWT
JSON Web Token. , , JWT.
, , , , . , , ( - , ). , .
, . ( , , ).
hello-world , , -, , .
compile('org.springframework.boot:spring-boot-starter-security')
compile('io.jsonwebtoken:jjwt:0.7.0')
. :
private String getToken(final UserEntity user) {
final Map tokenData = new HashMap<>();
tokenData.put(TokenData.ID.getValue(), user.getId());
tokenData.put(TokenData.LOGIN.getValue(), user.getLogin());
tokenData.put(TokenData.GROUP.getValue(), user.getGroup());
tokenData.put(TokenData.CREATE_DATE.getValue(), new Date().getTime());
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, tokenDaysAlive);
tokenData.put(TokenData.EXPIRATION_DATE.getValue(), calendar.getTime());
JwtBuilder jwtBuilder = Jwts.builder();
jwtBuilder.setExpiration(calendar.getTime());
jwtBuilder.setClaims(tokenData);
return jwtBuilder.signWith(SignatureAlgorithm.HS512, key).compact();
}
key
, . , , .
, . user-service
, service-client
, .. .
:
public class TokenAuthenticationFilter extends GenericFilterBean {
private final TokenService tokenService;
public TokenAuthenticationFilter(final TokenService tokenService) {
this.tokenService = tokenService;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final String token = ((HttpServletRequest) request).getHeader(TokenData.TOKEN.getValue());
if (token == null) {
chain.doFilter(request, response);
return;
}
final TokenAuthentication authentication = tokenService.parseAndCheckToken(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
}
token , . , () spring security. TokenService
, :
public class TokenService {
private String key;
public void setKey(String key) {
this.key = key;
}
public TokenAuthentication parseAndCheckToken(final String token) {
DefaultClaims claims;
try {
claims = (DefaultClaims) Jwts.parser().setSigningKey(key).parse(token).getBody();
} catch (Exception ex) {
throw new AuthenticationServiceException("Token corrupted");
}
if (claims.get(TokenData.EXPIRATION_DATE.getValue(), Long.class) == null) {
throw new AuthenticationServiceException("Invalid token");
}
Date expiredDate = new Date(claims.get(TokenData.EXPIRATION_DATE.getValue(), Long.class));
if (!expiredDate.after(new Date())) {
throw new AuthenticationServiceException("Token expired date error");
}
Long id = claims.get(TokenData.ID.getValue(), Number.class).longValue();
String login = claims.get(TokenData.LOGIN.getValue(), String.class);
String group = claims.get(TokenData.GROUP.getValue(), String.class);
TokenUser user = new TokenUser(id, login, group);
return new TokenAuthentication(token, true, user);
}
}
TokenData
enum , . TokenUser
( ) TokenAuthentication
:
public class TokenAuthentication implements Authentication {
private String token;
private Collection