I have a set of rest controllers written in java. The original requirement was to add some headers for some endpoints, but we decided to add these header fields in almost all rest controllers. The project now contains more than 100 similar APIs:
@getmapping("/products/{comp}") public responseentity<list<product>> getallproducts( @requestheader(user_hdr) string user, @requestheader(guid_hdr) string guid, @requestheader(value = caller_hdr, required = false) string caller, @requestheader(value = lang_hdr, required = false) string language, @pathvariable @notnull integer comp ) { return responseentity.ok(service.get(comp, productutils.processheaders(user,guid,caller,language))); } @getmapping("/products") public responseentity<list<product>> getallproducts( @requestheader(user_hdr) string user, @requestheader(guid_hdr) string guid, @requestheader(value = caller_hdr, required = false) string caller, @requestheader(value = lang_hdr, required = false) string language ) { return responseentity.ok(service.getallrecords(productutils.processheaders(user,guid,caller,language))); }
It is obvious from the code that the tuple user, guid, caller, language are everywhere in the source code, but, how to refactor and put the code in "one place" or try to make it richer, Isn't it obvious? Maintainable. For example, if we need to add a 5th parameter, we need to use 100 apis.
What is the canonical way to do this in java spring boot?
Ideally I would like something like this:
@GetMapping("/products/{comp}") public ResponseEntity<List<Product>> getAllProducts( "common handling" @PathVariable @NotNull Integer comp ) { return ResponseEntity.ok(service.get(comp, ProductUtils.processHeaders(user,guid,caller,language))); } @GetMapping("/products") public ResponseEntity<List<Product>> getAllProducts( "common handling" ) { return ResponseEntity.ok(service.getAllRecords(ProductUtils.processHeaders(user,guid,caller,language))); }
Any ideas? Controller suggestions? anything else?
To solve the code duplication problem and make the code easier to maintain in a spring boot application, you can create a custom filter to Headers are extracted and processed before reaching the controller. In addition, you can also encapsulate header parameters into objects to enhance the readability and maintainability of the code.
In summary, centralize header processing by creating a requestheaders
dto, implementing customheaderfilter
, and registering it with a filterregistrationbean
to unify it in the spring boot controller Apply common headers.
The following are recommended methods:
Create header dto (data transfer object):
Define a class representing public header parameters. This class will hold the value extracted from the header.
public class requestheaders { private string user; private string guid; private string caller; private string language; // getters and setters }
Create filter:
Implement filters to intercept incoming requests and extract public headers, then store them in request properties.
import org.springframework.web.filter.onceperrequestfilter; import javax.servlet.filterchain; import javax.servlet.servletexception; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import java.io.ioexception; public class customheaderfilter extends onceperrequestfilter { @override protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain filterchain) throws servletexception, ioexception { requestheaders headers = new requestheaders(); headers.setuser(request.getheader("user")); headers.setguid(request.getheader("guid")); headers.setcaller(request.getheader("caller")); headers.setlanguage(request.getheader("language")); request.setattribute("requestheaders", headers); filterchain.dofilter(request, response); } }
Use filterregistrationbean to register the filter:
Register custom filters using filterregistrationbean
in the main application class.
import org.springframework.boot.web.servlet.filterregistrationbean; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; @configuration public class webconfig { @bean public filterregistrationbean<customheaderfilter> customheaderfilter() { filterregistrationbean<customheaderfilter> registrationbean = new filterregistrationbean<>(); registrationbean.setfilter(new customheaderfilter()); registrationbean.addurlpatterns("/api/*"); // adjust the url pattern as needed return registrationbean; } }
Customize the addurlpatterns
method to match the urls you want the filter to apply to.
Modify the controller to use dto:
Modify your controller to use requestheaders
dto instead of separate header parameters.
@GetMapping("/products/{comp}") public ResponseEntity<List<Product>> getAllProducts(@PathVariable @NotNull Integer comp, @ModelAttribute("requestHeaders") RequestHeaders headers) { return ResponseEntity.ok(service.get(comp, headers)); } @GetMapping("/products") public ResponseEntity<List<Product>> getAllProducts(@ModelAttribute("requestHeaders") RequestHeaders headers) { return ResponseEntity.ok(service.getAllRecords(headers)); }
Now, if you need to add new header parameters or make changes, you only need to update the requestheaders
class and filter logic. This approach centralizes header processing and enhances maintainability.
The above is the detailed content of Duplication of RequestHeader in Java Spring Boot controller. For more information, please follow other related articles on the PHP Chinese website!