Como usar minha interface Service fora de uma classe RestController(SpringBoot)

Olá pessoal,
Estou desenvolvendo um micro-serviço com SpringBoot e estou tentando validar o email que a pessoa manda verificando se já existe em minha base dados.
Porque estou fazendo isso?
A ideia é criar uma validação antes que chegue na camada de persistência, evitando exceptions do banco e retornando uma mensagem amigavel, o meu maior problema é como eu consigo usar a interface PessoaService que acessa a camada de persistência fora da classe PessoaController que tem a anotação @RestController

public interface PessoaService {

public Pessoa save(Pessoa pessoa);
public Pessoa update(Pessoa pessoa);
public Pessoa findById(Long id);
public void delete(Long id);
public List findAll();
}

Implementação da Interface

@Service
public class PessoaServiceBean implements PessoaService {

@Autowired
private PessoaRepository dao;

@Override
public Pessoa save(Pessoa pessoa){
// TODO Auto-generated method stub

  	Pessoa p1 = dao.save(pessoa);
  	return p1;

}

Minha classe Controller

@RestController
public class PessoaController {

@Autowired
private PessoaService dao;

@SuppressWarnings(“rawtypes”)
@RequestMapping(
value="/api/pessoas",
method=RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity salvar(@RequestBody Pessoa pessoa) throws Exception{

  ExceptionThrower e = new ExceptionThrower();
  e.trhowMandatorio(pessoa);
  
  Pessoa objPessoa = pessoa;			
  dao.save(pessoa);
  return new ResponseEntity<Pessoa>(objPessoa, HttpStatus.CREATED);	

}

Minha Classe que trata os erros, a única forma que achei foi chamando minha API para poder fazer esse teste mas ai não fica legal

public class ExceptionThrower {

@Autowired
RestTemplate rs = new RestTemplate();

public void trhowMandatorio(Pessoa pessoa) throws CustomException {
CustomException e = new CustomException();

  if (validateEmail(pessoa.getEmail()) == true) {
  	e.setCode(HttpStatus.CONFLICT);
  	e.setMessage("Email ja cadastrado");
  	throw e;
  } else {
  }

}

private boolean validateEmail(String email) {
boolean teste = false;
String obj = rs.getForObject(“http://localhost:8080/servicopessoa/api/pessoas”, String.class);
JSONArray l = new JSONArray(obj);
if (l.length() > 0) {
for (int i = 0; i < l.length();i++) {

  		JSONObject json = l.getJSONObject(i);
  		if (email.equals(json.get("email"))){
  			teste = true;
  			return teste;
  		}
  	}
  } else {
  	return teste;
  }
  return teste;

}

quem puder dar essa força agradeço desde já!!!

Olá @zefinir vejo que você é novo em Spring Framework :grinning:.

Pelo que análisei do seu código tem muita coisa a ser ajustada, na parte de micro-service recomendo que você use Spring Cloud Netflix que já é possui toda a arquitetura de micro-service pronta para usar, só basta configurar o seu comportamento e além do mais trata load balance, roteamento entre os micro-services, tolerância a falha e entre outras coisas. Vou lhe passar esse link caso você tenha interesse em usar.
http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html

Outra coisa eu vi que você implentou a validação na mão, pois então, existe uma maneira mais simples, bonita e rápida de validação, chamada de Java Validatio no link a seguir tem uma exmplo de uso com Spring MVC.

Outra implementação complementar:
http://hibernate.org/validator/

Sobre o porque de sua classe PessoaService só funcionar em @RestController é porque ela é um Bean injetavél, pois você está usando um padrão chamada Injeção de Depedência. Outra coisa sua classe pode ser injetada em qualquer classe que esteja anotada diretamente com @Component ou de outra anotação que seja herdade @Component, que no caso de @RestController herda de @Component.

Mais qualquer outras dúvidas só perguntar, estamos aqui para ajudar :smiley:;

Eu tinha pesquisado bastante sobre microservices e como implementar, como está muito recente ainda não tem muito material explicando, lendo o blog do Martin fowler ele comentou sobre o Netflix OSS, então fui atrás porém achei muito complexo de implentar, com mais pesquisas achei o springBoot foi onde achei mais fácil de trabalhar, mas pelo o que você está dizendo do jeito que estou implementando seria somente um serviço RestFull certo?

Então essa implementação que estou fazendo na mão é para gerar mensagens amigaveis ao cliente, ao invés de sempre estourar um exception e mandar um HttpCode 500 Internal server error.
Com esse validations que você mandou eu consigo evitar um exception?

Olá @zefinir novamente.

Para a primeira pergunta, a resposta é sim, no seu caso vejo que você não está utilizando o conceito de micro-service, mas sim de webservice.

Para a segunda pergunta, a resposta é não, mas tem como você tratar a exception e enviar as mensagens de error de validação para a aplicação cliente atráves de Exception Handling do Spring MVC.

Eu criei um gist de como eu uso para validar e mandar as mensagens de error para a aplicação cliente.

Qualquer dúvida só perguntar novamente.

Att.
Emanuel Batista

Eu estava usando esse exemplo mesmo, mas só conseguia mandar um HttpCode personalizado, porque vamos supor no cadastro eu tenho campos que são requeridos que devem ser enviados e o email é unico na base de dados não pode se repetir, então para campos obrigatórios eu teria que mandar um 403 campos requeridos não informados, e caso o email já existe na base de dados enviar um 409 email já cadastrado e vendo esse video https://youtu.be/Mmh78Yf_6AM que achei e deu certo na forma que eu queria implementar, mas vou tentar usando esses validations e te falo se obtive sucesso.

ah só para complementar quem consumirá essa API será um cliente mobile.

Olá,

O problema da validação para campo único é a concorrência.
Exemplo: dois usuários preencheram o formulário usando um mesmo e-mail e esse e-mail não está no banco, então a validação vai passar mas quando for gravar os dados no banco um desses usuários irá reclamar pois somente uma gravação terá sucesso, uma vez que no backend você verifica se o e-mail já existe antes de gravar os dados.

Mesmo assim, uma pergunta que você deve fazer para si mesmo é: esse processo no backend de verificar se o e-mail existe e em seguida gravar os dados é atômico ? Caso o e-mail não exista, existe a possibilidade por menor que seja de uma gravação ter sucesso e a outra não.

Como resolver isso: tornar o campo e-mail único no banco ou usar transação no método que faz a verificação de e-mail e gravação, assim garantido a atomicidade.

Lembram-se de concorrência de threads e a utilização de monitores, semáforos e métodos synchronized do Java SE ?! Somente uma thread de cada vez pode executar esse método pois o monitor só deixa um de cada vez.

Espero ter sido claro o suficiente.

1 curtida