I'm working on a spring web application using thymeleaf as a view resolver lately, and when developping my controllers, i faced a new situation :
i'm not really sure about it but can the #Pathvariable passed from the view be an object ? (a compound key of a model to be precise ? )
i used ids before, but most of them were simple int ids, i just want to know if passing an object (which is the primary key of my object) is possible , and not simple int ids ?
And Thank you
You can use Spring PropertyEditor or Spring Converter see Spring Convertor
example
public class CategoryConverter implements Converter<String, Category>{
#Autowired
private CategoryService categoryService;
public Category convert(String id) {
return categoryService.findById(Long.valueOf(id));
}
}
But you may meet some problem when saving object directly to database.
Related
I want SpringBoot to be able to provide default values for fields that the user must enter. For example, I have something like this:
*Controller class*
#PostMapping("/test")
public ResponseEntity<> myMethod(#RequestBody #Valid MyContract contract) {}
*MyContract class*
#Valid
DataObject dataObject;
*DataObject class*
#Component
public class DataObject {
private #Value("${field1.default}") String field1Default;
private String field1
public String getField1() {
return (field1 == null ? field1Default : field1);
}
}
The DataObject class needs to be created on a per request basis. There are also other places in the code where it needs to be created on demand. So I imagine it needs to be a Prototype object. But I can't figure out how to get Spring to created it properly when it creates it for the request.
Update
I have read more about #RequstBody, e.g., https://www.javadevjournal.com/spring/spring-request-response-body/ and Should spring #RequestBody class be singleton or prototype?, which explains that the object is not a Component, but a simple POJO that gets the values from the Json request. So it seems that there is no way to inject #Values from the Spring application.properties file. Is there any other way around this? Or another suggested implementation?
I'm having some trouble implementing a function over some pre-existing code.
Other programmers working on this project previously defined a genric abstract "restcontroller" (it's not actually annotated as #RestController but it's meant to be extended by classes with that annotation)
public abstract class AbstractController<T extends AbstractEntity, R extends JpaRepository<T, Integer>> {
#GetMapping(value = "/getall")
public Paging<T> getAll(#RequestParam Integer itemsPerPage,
#RequestParam Integer pageIndex,
#RequestParam Map<String, String> filters,
#Autowired Consumer consumer) {
//Fetch entities of type T from repository R and return them
}
//other generic crud operations
}
This class is usually extended by concrete controllers that simply define other operations on their specific types, but do no alter generic crud operations.
What I want to do is extend this class, but override the getAll method, like this:
#RestController
#RequestMapping("/api/tasks")
public class TaskController extends AbstractController<Task, TaskRepository> {
#Override
public Paging<Task> getAll(Integer itemsPerPage, Integer pageIndex, Map<String, String> filters, Consumer consumer) {
LoggerFactory.getLogger(LazyTaskController.class).log("function called successfully!");
Paging<Task> paging = super.getAll(itemsPerPage, pageIndex, filters, consumer);
//do things with return value before returning
return paging;
}
}
If I call BASEURL/api/tasks/getall?itemsPerPage=25&pageIndex=0 without overriding the getAll method, the parameters are wired correctly (the Map contains two values, itemsPerPage and pageIndex, as expected, and consumer contains a concrete implementation of the intercace Consumer).
However if I do override it, the Map for some reason contains two values, one with key "consumer" and type Proxy, and another with key "org.springframework.validation.BindingResult.consumer" and value of type BeanPropertyBindingResult; and consumer contains a Proxy.
I suppose the #Override interferes with the autowiring of Consumer, but I can't figure out how to properly achieve what I have in mind (manipulating the results of getAll before returning them).
Thank you in advance
Nevermind, I solved it.
The problem with the Map was solved by adding #RequestParam and #Autowired annotations to the overridden method parameters as well.
The problem with the Consumer concrete type was somehow solved by applying a custom annotation that I found on another class in the codebase, I'm still not sure about what that annotation does but at least I know what to look for now.
I am building a REST API using spring and hibernate. I have come across the issue where I want to create a user and want to know the best practice on how to validate that the user can be created.
My controller has the #Valid annotation on the User object that gets passed into the method, and this checks for valid structure, however there is no #Unique property that gets picked up by #Valid.
I am using the #Column(unique = true) but this throws an error at the persistence level and I feel like that is quite low level and makes it difficult to throw a custom UsernameAlreadyExistsException().
My question here is what is the best practice in terms of preforming this type of validation. I thought about creating a custom annotation but it seems quite messy especially because as the project grows I would need multiple validators for different fields and it also seems to be closley related to tying the service layer to the annotation which seems messy
In my opinion, using custom annotation is the best approach to do stuff like this, you can inject some bean in ConstraintValidator and perform validation. However you can try one of the below unusual approaches, maybe it will fit your requirements.
Spring AOP
Spring Handler Interceptor
JPA Event Listeners
It's just my opinion about this, in most cases I think I will create custom annotations to handle it.
A good practice would be to put validation both on the database (which we know nothing about, but it is not complicated really) and on the Spring's side.
As #kamil-w already said, a good is to write custom constraint validator, see here for an example.
Keep in mind that you can always pass parameters like to constraint annotation, and then access them in your ConstraintValidator, for example.:
#Entity
public class Member {
// ...
#UniqueField(fieldName = "login", context = Member.class)
private String login;
}
#Component
public class UniqueFieldValidator implements ConstraintValidator<UniqueField, Object> {
#PersistenceUnit
private EntityManagerFactory emf;
private Class validationContext;
private String fieldName;
#Override
public void initialize(UniqueField uniqueField) {
this.validationContext = uniqueField.validationContext();
this.fieldName = uniqueField.fieldName();
}
#Override
public boolean isValid(Object value, ConstraintValidatorContext cxt) {
// use value, this.validationContext, this.fieldName and entity manager to check uniqueness
}
}
I have some data objects that are common across a Spring boot application - one is the logged in employee object and other is a category. I have created a #Component class which contains these are static variables. This way I do not even have to autowire them. They can be used directly like CurrentContext.employee in controllers.
#Component
public final class CurrentContext {
public static Category currentCategory;
public static Employee employee;
#Autowired
private CategoryService categoryService;
#Autowired
private EmployeeService employeeService;
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
currentCategory = categoryService.getCategory();
}
#EventListener
public void onLoginSuccess(InteractiveAuthenticationSuccessEvent event) {
employee = employeeService.getEmployeeByUserId(((MyUserDetails) event.getAuthentication().getPrincipal()).getUserId());
}
}
Is this a right way? Please suggest if there is a better way to handle shared data
Edit
Some background - I require the current logged in employee and a category which is common for all employees. So I autowired employeeService and categoryService in my controllers and use them to get the data. They are required in almost all my controller methods, so, I wanted to create a bean of these so that I directly use them in my controller and also save frequent database calls.
Normally, we only put the dependencies related to the cross-cutting concerns (i.e dependencies that are across the whole application such as security , logging , transaction stuff , time provider etc.) in the static field.
By accessing these kind of dependencies in the static way , we don't need to pass them through method parameters /constructors from object to object , which will make the API much cleaner without such noise (BTW. This is called Ambient Context Pattern in the .NET world).
Your Employee object most probably belong to this type , so it is ok to access it in a static way. But as their scope is per session , you cannot simply put it in the static field of a class. If yes, then you always get the same employee for all sessions. Instead, you have to somehow store it in an object which is session scope (e.g HttpSession) . Then at the beginning of handling a web request , you get it from the session and then put it in a ThreadLocal which is encapsulated inside a "ContextHolder" object. You then access that "ContextHolder" in a static way.
Sound very complicated and scary ? Don't worry as Spring Security has already implemented this stuff for you. What you need to do is to customize Authentication#getPrincipal()or extend default Authentication to contain your Employee. Then get it using SecurityContextHolder.getContext().getAuthentication()
For your currentCategory , if they are not the cross-cutting concerns and is the application scope , make a singleton bean to get it values is a much better OOP design.
#Component
public final class CurrentCategoryProvider {
#Autowired
private CategoryService categoryService;
public Category getCurrentCategory(){
//or cache the value to the an internal properties depending on your requirements
return categoryService.getCategory();
}
}
You then inject CurrentCategoryProvider to the bean that need to access currentCategory.
I have requirement for spring mvc 3 caching. Requirement is : while starting the server, we need to call database for one dropdown and put those values in the cache. So that whenever we required those values, we need to retrieve from cache.
Please help me with an example.
Thanks in advance.
May be you can use init-method (Spring 2.5) or #PostConstruct annotation (in Spring 3.0).
This method will be called during server start up
The following is code snippet
#Component
public class CacheDBData {
private String values[];
//add setter & getter
//This will be called during server start up after properties are initialised
#PostConstruct
public void getDataFromDB() {
values = //Logic to get data from DB and store that in values property
}
}
Suppose for example you can use in class as follows
#controller
public class HomeController {
#Autowired
private CacheDBData cacheDBData ;
//getter and setters
private void methodxyz() {
String values[] = cacheDBData.getValues();
}
}
I've had success with Ehcahe for Spring. There's a couple of config files to setup but after that you simply annotate the methods you want to cache the output from and it just works.
This has the advantage that you can change the values coming back from the service/database and NOT have to restart your app, unlike the accepted answer.