I have a simple controller in Spring Boot application
#GetMapping("/")
public Page<StockDto> listStocks(Pageable pageable) {
return stockService.list(pageable);
}
It calls list method in StockService to get a list of items from the database. StockRepository is a class that extends JpaRepository with a #Repository annotation.
#Service
public class StockService {
private StockRepository stockRepository;
private ModelMapper modelMapper;
#Autowired
public StockService(StockRepository stockRepository, ModelMapper modelMapper) {
this.stockRepository = stockRepository;
this.modelMapper = modelMapper;
}
public Page<StockDto> list(Pageable pageable) {
Page<StockEntity> stockEntities = stockRepository.findAll(pageable);
return stockEntities.map(stockEntity -> modelMapper.map(stockEntity, StockDto.class));
}
}
The JSON result of calling API has content, pageable, and some other fields.
I didn't use Spring Data Rest too. Now I want to add two Next and Prev strings that have next and previous links of getting resource in response JSON.
Related
I am working on webclient for various HTTP methods (GET,PATCH,POST,DELETE). These are created separately and invoke separately. I am looking to make it as a generic webclient component so minimum changes needs to do in the future. Below is the code for GET and POST. PATCH and Delete is also on similar lines. Please let me know how can I proceed to make generic webclient for various HTTP methods.
#Component
public class HuntsCreateNewCollectionAdapter {
#Autowired
AppProperties properties;
#Autowired
WebclientCollectionConfig webclientCollectionConfig;
public Mono<ResponseEntity<HuntsCollectionDto>> createCollectionAPI(RequestContext context, String title) {
LOGGER.debug("Create Collection API call");
CollectionInputDto collectionInput = CollectionInputDto.builder().title(title).build();
String json = AppJsonUtil.getJsonAsString(collectionInput);
Mono<ResponseEntity<HuntsCollectionDto>> result = webclientCollectionConfig.collectionBuilder().post()
.uri(properties.getCollectionUrl())
.headers(header -> header.addAll(webclientCollectionConfig.getHeaders(context)))
.body(BodyInserters.fromValue(json)).exchangeToMono(response -> {
return response.toEntity(HuntsCollectionDto.class);
});
return result;
}
}
#Component
public class HuntsGetCollectionAdapter {
#Autowired
AppProperties properties;
#Autowired
WebclientCollectionConfig webclientCollectionConfig;
public Mono<ResponseEntity<HuntsCollectionDto>> getCollectionAPI(RequestContext context, String collectionId) {
LOGGER.debug("Get Collection API call");
return webclientCollectionConfig.collectionBuilder().get()
.uri(properties.getCollectionUrl() + "/" + collectionId)
.headers(header -> header.addAll(webclientCollectionConfig.getHeaders(context)))
.exchangeToMono(response -> {
return response.toEntity(HuntsCollectionDto.class);
});
}
}
#Component
public class WebclientCollectionConfig {
#Autowired
AppProperties appProperties;
#Bean
public WebClient collectionBuilder() {
return WebClient.builder().baseUrl(appProperties.getCollectionbaseUrl())
.defaultHeader("Content-Type", "application/json").build();
}
}
I am missing something here. I am attempting to pull information using Spring Boot WebClient from a Dummy Api that's an Http request. I am not getting any info pulled when I go into postman.
Thanks for any insight you can give me. I am still very new to coding and self-taught.
Here's my employee controller:
#Autowired
WebClientApp webClientApp;
#GetMapping("/consume")
public String getEmployee(Model model) {
model.addAttribute("listEmployees", empServiceImpl.getAllEmployees());
model.addAttribute("listemps", webClientApp.webClientBuilder());
return "index";
}
Web Client
private WebClient webClient;
public void SimpleWebClient(WebClient webClient) {
this.webClient = webClient;
}
public Flux<Employee> webClientBuilder() {
return this.webClient
//this.webClientBuilder = webClientBuilder.baseUrl(DummyEmployee)
.get()
.uri("api/v1/employees")
.retrieve()
.bodyToFlux(Employee.class);
}
Employee
#Data
#ToString
//#AllArgsConstructor
//#NoArgsConstructor
#JsonRootName(value = "data")
public class Employee {
#JsonProperty("id")
public int employeeID;
#JsonProperty("employee_name")
public String employeeName;
#JsonProperty("employee_salary")
public String employeeSalary;
#JsonProperty("employee_age")
public int employeeAge;
#JsonProperty("employee_image")
public Blob employeeImage;
}
Service
#Repository
#ComponentScan(basePackages = {"com.example.app.repository"})
#Service
public class ServiceImpl implements EmpService{
#Autowired
private EmployeeRepository employeeRepo;
#SuppressWarnings("unchecked")
public List<Employee> getAllEmployees() {
return (List<Employee>) employeeRepo.findAll();
}
}
Service
#Service
public interface EmpService {
static List<Employee> getAllEmployees() {
// TODO Auto-generated method stub
return null;
}
}
Main
public static void main(String[] args) {
SpringApplication.run(RestWebsiteDataProjectApplication.class, args);
}
#Bean
public WebClient webClientFromScratch() {
return WebClient.builder()
.baseUrl("https://dummy.restapiexample.com/")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
Flux only emits its content when it is subscribed. You are not subscribing to the Flux returned by the webClientBuilder() method.
You shouldn't really do this, but try adding .block() to your Controller as follows:
#Autowired
WebClientApp webClientApp;
#GetMapping("/consume")
public String getEmployee(Model model) {
model.addAttribute("listEmployees", empServiceImpl.getAllEmployees());
model.addAttribute("listemps", webClientApp.webClientBuilder().block());
return "index";
}
If this works, please consider reworking your code because while working with Spring WebFlux (reactive programming) you should always deal with Mono and Flux so that you can take full advantage of the reactive stack.
I have implemented a simple Spring Data REST repository which works as expected and I am fine with it exposing all methods. This is what it looks like:
#RepositoryRestResource(path = "employees")
public interface EmployeeRepository extends PagingAndSortingRepository<Employees, Integer>
{ }
Now I would like to wrap this repository in a controller, so I can later add Hystrix to it for fallbacks and exception handling. My issue is now, that I would like to keep the behavior of the repository above and just pass the response through the controller to the client. Is there a possible way without reimplementing all the methods of my repository (including sorting and pagination)?
This is what my controller currently looks like:
#RepositoryRestController
public class EmployeeController {
private final EmployeeRepository repository;
#Autowired
public EmployeeController(EmployeeRepository repo) {
repository = repo;
}
// Here I would like to return the same respone as my repository does
#RequestMapping(method = GET, value = "/employees")
public #ResponseBody ResponseEntity<?> parseRequest() {
return ResponseEntity.ok("hi");
}
}
It seems that you could simply call the method from your repository. Did you try it?
#RepositoryRestController
public class EmployeeController {
private final EmployeeRepository repository;
#Autowired
public EmployeeController(EmployeeRepository repository) {
this.repository = repository;
}
#RequestMapping(method = GET, value = "/employees")
public #ResponseBody ResponseEntity<List<Employee>> parseRequest() {
List<Employee> employees = repository.getEmployees();
return new ResponseEntity(employees, HttpStatus.OK);
}
}
i have created a custom rest controller and I can access the API and get the result from the resource, the problem is, it doesn't appear in the HAL Browser.. how to expose this custom method in the HAL Browser? Thank You...
#RepositoryRestController
public class RevisionController {
protected static final Logger LOG = LoggerFactory
.getLogger(RevisionController.class);
private final DisciplineRepository repository;
Function<Revision<Integer, Discipline>, Discipline> functionDiscipline = new Function<Revision<Integer, Discipline>, Discipline>() {
#Override
public Discipline apply(Revision<Integer, Discipline> input) {
return (Discipline) input.getEntity();
}
};
#Inject
public RevisionController(DisciplineRepository repository) {
this.repository = repository;
}
#RequestMapping(method = RequestMethod.GET, value = "/disciplines/search/{id}/revisions")
public #ResponseBody ResponseEntity<?> getRevisions(
#PathVariable("id") Integer id) {
Revisions<Integer, Discipline> revisions = repository.findRevisions(id);
List<Discipline> disciplines = Lists.transform(revisions.getContent(),
functionDiscipline);
Resources<Discipline> resources = new Resources<Discipline>(disciplines);
resources.add(linkTo(
methodOn(RevisionController.class).getRevisions(id))
.withSelfRel());
return ResponseEntity.ok(resources);
}
}
Register a bean that implements a ResourceProcessor<RepositoryLinksResource> and you can add links to your custom controller to the root resource, and the HAL Browser will see it.
public class RootResourceProcessor implements ResourceProcessor<RepositoryLinksResource> {
#Override
public RepositoryLinksResource process(RepositoryLinksResource resource) {
resource.add(ControllerLinkBuilder.linkTo(ControllerLinkBuilder.methodOn(RevisionController.class).getRevisions(null)).withRel("revisions"));
return resource;
}
}
I made web service with spring mvc(version 4).
This service used token in http header for authorization.
I want to value in http header bind to field in model class auto.
Is it possible? How can I do?
(See below code and comment)
Controller
#Controller
#RequestMapping(value = "/order")
public class OrderController {
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
#Autowired
private OrderService orderService;
#RequestMapping(value = "/")
#ResponseBody
public List<Order> getAll() throws Exception {
// I want to remove two line below with auto binding (userToken field in model)
// in all controller using token value
String token = request.getHeader("X-Auth-Token"); // remove~
orderService.setUserToken(token); // remove~
orderService.getAllbyUser()
return items;
}
}
Model(Service)
#Service
public class OrderService {
//#Autowired - is it possible?
private String userToken;
public String setUserToken(String userToken)
{
this.userToken = userToken;
}
public List<Order> getAllbyUser() {
String userId = userMapper.getUserId(userToken);
List<Order> list = orderMapper.getAllbyUser(userId);
return list;
}
}
#Autowire is for Spring to inject beans one to another. If you want to inject a String to a bean you can with the org.springframework.beans.factory.annotation.Value annotation.
For example:
#Value("${user.token}")
private String userToken;
This will make Spring search of the user.token in the VM args and other places (which I don't remember and in some specific order).
But again, as said in my initial comment, from the code you show here it seems to be an error setting this field as it is context specific and the #Service (by default) indicates that the OrderService is a singleton.
In order to read a header value from request, you can use #RequestHeader("X-Auth-Token") in your controller, as shown below:
#RequestMapping(value = "/")
#ResponseBody
public List<Order> getAll(#RequestHeader("X-Auth-Token") String token) throws Exception {
orderService.setUserToken(token); // remove~
orderService.getAllbyUser()
return items;
}
Hope this helps you.