Set model attribute during a resource phase Spring MVC - spring-mvc

I need to update my model attribute inside a resource method. The thing is that, after update it, I'd need to set this new modified bean in the model, in order to get the right timestamp to do the next operation when some action method be called.
I have my bean with
#SessionAttributes(ServletContextKeys.MY_BEAN)
and
#ModelAttribute(ServletContextKeys.MY_BEAN)
anotations, so I get my bean from the session in the resource method, but after update it, I've no idea how to access the model in the resource phase or any other possible workarround to solve this issue.
#ResourceMapping(ServletContextKeys.MY_RESOURCE_METHOD)
public final void updateDoc(){
MyBean myBean = getBeanFromSession();
MyBean myNewBean = myService.updateDocs(myBean); //This mehod will change the timestamp and return the updated bean
//Now I'd like to set the bean in the model. How could I access it?
model.addAttribute(ServletContextKeys.MY_BEAN, myNewBean);
}

Related

How to access Magnolia v5.7 component property from Model java class

I have defined property in component dialog
How I can access this value from execute() method in model class?
Model class will request service at this url
Documentation discusses only how to access data within Model class, I need to pass url into Model class.
I can't send request from page by ajax, because service domain not exposed to extranet.
Your model class extends from RenderingModelImpl. Or at least it should :).
Because of that there's a constructor that get passed current component node in and it's exposed to you via getNode() method.
So assuming that when you click on Save changes in your dialog, the value gets persisted under unsubscribeUrl property, to access this value from execute() method:
public String execute() {
// read unsubscribe url
String unsubscribeUrl = this.getNode().getProperty("unsubscribeUrl").getString();
}
In your ftl you can call the model with an argument:
${model.myMethod(content.unsubscribe_url)}
In your model you can use the argument to do what you need
public class myMethod(String url) {
do something ....
}

springboot+mybatis, About Native Dao development

I'm trying a new development method.
In mybatis3, I write mapper.java and mapper.xml usually.
I know, the sql statements is corresponded by sqlId(namespace+id).
I want to execute the sql statement like this :
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
but I get a error:
Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mapper.JinBoot.test
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at cn.tianyustudio.jinboot.dao.BaseDao.select(BaseDao.java:20)
at cn.tianyustudio.jinboot.service.BaseService.select(BaseService.java:10)
at cn.tianyustudio.jinboot.controller.BaseController.test(BaseController.java:21)
here is my BaseDao.java
public class BaseDao {
private static SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
public static List<Map> select(String sqlId, Map param) {
try {
factoryBean.setDataSource(new DruidDataSource());
SqlSessionFactory sessionFactory = factoryBean.getObject();
SqlSession sqlSession = sessionFactory.openSession();
return sqlSession.selectList(sqlId, param);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
here is UserMapper.xml
<mapper namespace="mapper.JinBoot">
<select id="test" parameterType="hashMap" resultType="hashMap">
select * from user
</select>
</mapper>
the application.properties
mybatis.mapperLocations=classpath:mapper/*.xml
I start the project, the send a http request, after controller and service ,the param 'sqlId' in BaseDao is 'mapper.JinBoot.test' (see error info).
In method 'BaseDao.select', both the parameter and the result type is Map.
So I don't want to create UserMapper.java, I want try it.
How can I resolve it? What's the malpractice of this way?
This does not work because spring boot creates its own SqlSessionFactory. And the option in application.properties that specifies where mappers should be looked for is only set for that SqlSessionFactory. You are creating unrelated session factory in your DAO and it does not know where to load mappers definition.
If you want to make it work you need that you DAO is spring managed so that you can inject mybatis session factory into it and use it in select. This would also require that you convert select into non static method.
As I understand you want to have only one method in you base DAO class and use it in individual specific DAO classes. I would say it makes little sense. If the method returns Map there will be some place that actually maps this generic type to some application specific types. This would probably be in the child DAOs. So you still need to create the API of the child DAO with the signature that uses some input parameters and returns some domain objects. And that's exactly what you want to avoid by not creating mybatis mapper classes.
The thing is that you can treat your mytabis mappers as DAOs. That is you mappers would be your DAOs. And you don't need another layer. As I understand now you have two separate layers - DAO and mappers and you want to remove boilerplate code. I think it is better to remove DAO classes. They are real boilerplate and mybatis mapper can serve as DAO perfectly. You inject it directly to you service and service depends only on the mapper class. The logic of the mapping is in the mapper xml file. See also answer to this question Can Spring DAO be merged into Service layer?

spring mvc bean scope singleton seem not work properly

Please help me
I am new spring mvc user. In controller i call a singleton bean like that:
#RequestMapping(value = "/student", method = RequestMethod.GET)
public ModelAndView student(#RequestParam(required = false) String name) {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] { "mvc-dispatcher-servlet.xml" });
Student student = (Student) context.getBean("student");
if (name != null && name.length() > 1) {
student.setName(name);
}
System.out.println("name:" + student.getName());
return new ModelAndView("result", "student", student);
}
The first time, i enter url in browser: http://localhost:8080/example/student?name=myname
The system print result like that: name:myname=> it's ok
The second time, i enter url in browser: http://localhost:8080/example/student
The system print result like that: name:null
Why? you said that a single bean instance be created for every request?
So the first time the name of student was set is "myname". The second time, when i request again, if a single bean instance was created, the name of student must be "myname", because it was set in first time request?But in my case, the second time request, seem that a new bean instance be created? So the name value is null
Thanks very much
Spring is doing what you have exactly asked for.
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] { "mvc-dispatcher-servlet.xml" });
Everytime you are making a request, you are creating a new instance of parent context. And hence you are not getting the bean with a singleton scope.
When you use ,
#Autowired private Student student
you are not creating context for every request. Hence your bean is getting created with a singleton scope.
Singleton instance means through out the applications only single instance of bean will be created by the spring containers like BeanFactory or ApplicationContext.
When ever you supplied your *.xml configuration file to BeanFactory or ApplicationContext containers then they will read specified bean declarations and starts instantiate them as singleton by default.
In your case you are specifying your *.xml to containers for each request to "/student" so, for every request of "/student" instances will be created.
study this link to configure your xml files to spring container for web applications
http://docs.spring.io/autorepo/docs/spring/3.2.x/spring-framework-reference/html/mvc.html

Get all annotated classes and call each method to get a return value

I am creating a small validation application using Spring MVC. I am very new to Spring MVC and would like to ensure that what I want is possible.
I have simplified my problem.
I have setup a controller that will be called when a URL is executed. localhost/validate/{SOME TEXT}
The {SOME TEXT} value with be sent to all my validation classes I created.
I currently have 4 classes which does the validation and returns another Object data about what happened during the validation
The 4 validation classes are:
CreditCardValidator
AddressValidator
ZipcodeValidator
AccountNumberValidator
I have a main controller bean that when called I want the string to be passed to each class and the object returned from each to be stored and then finally all results are sent back in a response.
Normally, I would do this without Spring by creating an interface that each validation class implements. Then iteration through the list of classes and execute a method.
The problem doing it that way is that whenever I need to add a new validation class I'll need to register it so the request can use it. This involved modifying existing classes.
Since I am using Spring quick heavily in this application I am wondering if this is possible to do via Spring and annotated classes.
I was thinking of creating a custom annotation that each validation class has and then using spring component-scan to get the classes. This would allow me to create new validations without modifying existing code.
Below is the what I am trying to do.
#Controller
public class StringValidationController {
#RequestMapping(value = "/validate/{text:.+}", method = RequestMethod.GET)
public ModelAndView index(#PathVariable("text") String text) {
ModelAndView model = new ModelAndView();
model.setViewName("index");
model.addObject("result", getListOfValidatedData());
return model;
}
public List getListOfValidatedData(){
//Scan for IValidator annotation
//call each concrete class and pass in text
// get object with has validation information in it
}
}

#ModelAttribute and #SessionAttribute in Spring

As Spring Specification said, #ModelAttribute will executed before the mapping handler and #SessionAttribute will keep the model attribute in session.
Consider below scenario: form bean is created after the controller is called and is set as session attribute as well. Next time MenuController is called, createForm() will be executed again and create another new form bean. My question is: will this latest created form bean be set as session attribute? and which form bean will be bind to the parameter in method bookList()?
Hope you guys can help. Thank you.
#Controller
#RequestMapping("/store")
#SessionAttribute("form")
public class MenuController {
#ModelAttribute("form")
public Form createForm() {
return new Form();
}
#RqeustMapping("/book")
public String bookList(#ModelAttribute("form") Form form){
//processing the form
}
}
When the bookList method is invoked for the first time in a given session, then method with #ModelAttribute('form) is invoked, the returned value (Form object) is stored in HttpSession and finally the bookList method is invoked with the same Form object passed as an argument (obtained from session).
For the subsequent requests within the same HttpSession, Spring retrieves the same Form object from the session and doesn't call the method with #ModelAttribute('form') again till the end of the session.
After each end of the bookList method invocation Spring stores updated version of Form object in HttpSession.
If you are using Spring Boot 2.x you can debug DefaultSessionAttributeStore#retrieveAttribute method to understand this behaviour.
Remember that your mapping is generalised. It will map both to a GET method and a POST method.
If your request mapping is a GET method,
The session attribute will hold the value of the #ModelAttribute("form") from the method createForm.
If an attribute form is returned from a POST request,
The session Attribute will override the #Model Attribute from the createForm method.
It is helpful to remember that the #ModelAttribute will execute before the mapping handler.
the sessionAttribute indicates that the "form" will be saved in the session. not meaning the "form" is retrieved from the session.

Resources