I try Autowired My Service in class who extends AbstractJExcelView but is always null.
I'm guess i can solve this problem change Dependency Injection with Annotation to xml configuration and inject manual component.
Controller
#Controller
#SessionAttributes("user")
public class UserController {
#RequestMapping(value="/exportExel", method = RequestMethod.GET)
public ModelAndView getExelView(#ModelAttribute User user){
return new ModelAndView("ExelUserView","UserList",
user);
}
}
Service
#Service
public class UserServiceImp implements UserService {
#Override
public String getAllFood(User user) { //I Want Get All Element from model User
who contains Arrays String
String backValue = "";
for(String s : user.getFavFood()){
backValue +=s;
backValue +=",";
}
return backValue;
}
}
And ExelView
public class ExelView extends AbstractJExcelView {
private UserServiceImp userService = new UserServiceImp(); // I solve my problem that
//but in my controller i use Autowired Interface Service
// so i dont think its good solution
#Override
protected void buildExcelDocument(Map<String, Object> model,
WritableWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
WritableSheet sheet = workbook.createSheet("User Response", 0);
setExelHead(sheet);
User listUser = (User)model.get("UserList");
setExelRows(sheet, listUser);
}
public void setExelRows(WritableSheet sheet,User listUser) throws RowsExceededException, WriteException{
sheet.addCell(new Label(4, 1, userService.getAllFood(listUser)));
}
}
And User Model
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String[] favFood;
public String[] getFavFood() { //I want View Arrays in Exel in one Cell
return favFood;
}
public void setFavFood(String[] favFood) {
this.favFood = favFood;
}
}
in xml i use
<context:component-scan base-package="com.dinor913.example" /> // I guess delete auto scan component and inject Manual all Controller and Service and this should work then
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>
/WEB-INF/xml-views/document-views.xml
</value>
</property>
<property name="order" value="0"/>
</bean>
and document-views.xml
<bean name="ExelUserView"
class="com.dinor913.example.businnes.ExelView" >
</bean>
UPDATE SOLVE!
I Added to document-views.xml
<context:annotation-config base-package="com.dinor913.example" />
So i understand when i create XmlViewResolver i also create new ApplicationContext for XmlViewResolver and context:annotation-config add #Autowired UserService to DispatcherServlet.
Thx For help.
I Just Start Learn Spring a few days ago
Sorry for my terrible english i hope you understand what i mean.....
Change private UserServiceImp userService = new UserServiceImp(); to:
#Autowired
private UserServiceImp userService
This should work. If not post the errormessage and the stacktrace.
Related
I have a bit of code that is working :
#Component
public class MessageUtil {
#Autowired
#Qualifier("processMessages")
private ReloadableConfig config;
public String createMessage() {
return config.getPropertyStr("message.simple.signature");
}
}
The bean processMessages is defined here :
<bean id="processMessages" class="com.company.framework.resources.ReloadableConfig">
<property name="basename" value="classpath:com/company/aaa/bbb/domain/service/processMessages"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="cacheSeconds" value="60"/>
</bean>
Then I created some new classes :
public abstract class MessageBuilder {
#Autowired
#Qualifier("processMessages")
protected ReloadableConfig config;
public abstract String createMessage();
}
#Component
public class SimpleMessageBuilder extends MessageBuilder {
private String template;
private void setTemplate() {
template = config.getPropertyStr("message.simple.signature");
}
#Override
public String createMessage() {
setTemplate();
return template;
}
}
I now have a NullPointerException because in setTemplate(), config is null.
What's the problem in the second code ?
#Autowired doesn't work neither on field neither on constructors of abstract classes. It works on setter of abstract class but be sure to make it final because if overwritten by concrete class behavior is unstable. An abstract class isn't component-scanned since it can't be instantiated without a concrete subclass.
I am new to annotation based controller. I have two servlet like this:
pathA-servlet for url: pathA/*
pathB-servlet for url: pathB/*
And I have a controller like:
public class MyController extends SimpleFormController {
private MyService myService;
}
And two service implementation:
public class MyService1 implements MyService {
}
public class MyService2 implements MyService {
}
And in pathA-servlet:
<bean name="/doSomeThing" class="MyController">
<property name="myService" ref="myService"/>
</bean>
<bean id="myService" class="MyService1"/>
And in pathB-servlet:
<bean name="/doSomeThing" class="MyController">
<property name="myService" ref="myService"/>
</bean>
<bean id="myService" class="MyService2"/>
Now, I am trying to do the same with annotation based controller using: #Controller, #RequestMapping. How can I do that?
Here is a sample #Controller. This is a rest endpoint, you can access it with
#Controller
#RequestMapping(method = RequestMethod.POST, value = "/my")
public class CopyOfMyController {
#Autowired
private MyService service;
#RequestMapping(method = RequestMethod.POST, value = "/hib")
public void haha(#ResponseBody RequestDTO dto) {
service.doSomething(dto);
}
}
you can hit it with
Dto dto = new Dto();
dto.setPhone("12313");
RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(new URI("http://localhost:8080/my/hib"), dto, Dto.class);
It's very simple. In your controller, first add the #Controller annotation. This annotation simply says that this class will be a Spring controller that will be able to handle HTTP Requests based on the url mapping defined in the methods of your controller.
Also add an #Autowired annotation for the service attribute. Since there is 2 implementations of MyService, add the #Qualifier by passing the bean name because Spring would unable to choose which bean to inject otherwise.
So you can do something like this :
#Controller
public class MyController {
#Autowired
#Qualifier("bean1") // This should be bean1
private MyService myService1;
#Autowired
#Qualifier("bean2")
private MyService myService2;
#RequestMapping(value = "/doSomeThing1", method = RequestMethod.GET)
public String doSomething(){
return myService1.doSomething();
}
#RequestMapping(value = "/doSomeThing2", method = RequestMethod.GET)
public String doSomething(){
return myService2.doSomething();
}
}
I have class CandidateService marked as #Transactional
#Transactional
#Service("candidateService")
public class CandidateService {
#Autowired
private CandidateDao candidateDao;
....
public void add(Candidate candidate) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String login = auth.getName();
User user = utilService.getOrSaveUser(login);
candidate.setAuthor(user);
candidateDao.add(candidate);
}
...
}
dao implementation:
#Override
public Integer add(Candidate candidate) throws HibernateException{
Session session = sessionFactory.getCurrentSession();
if (candidate == null) {
return null;
}
Integer id = (Integer) session.save(candidate);
return id;
}
if I write in #controller class:
#RequestMapping("/submitFormAdd")
public ModelAndView submitFormAdd(
Model model,
#ModelAttribute("myCandidate") #Valid Candidate myCandidate,
BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return new ModelAndView("candidateDetailsAdd");
}
myCandidate.setDate(new Date());
candidateService.add(myCandidate);
.....
}
After executing this methods data put to database!
if I write test:
#ContextConfiguration(locations = {"classpath:/test/BeanConfig.xml"})
public class CandidateServiceTest extends AbstractTransactionalJUnit4SpringContextTests{
#Autowired
CandidateService candidateService;
#BeforeClass
public static void initialize() throws Exception{
UtilMethods.createTestDb();
}
#Before
public void setup() {
TestingAuthenticationToken testToken = new TestingAuthenticationToken("testUser", "");
SecurityContextHolder.getContext().setAuthentication(testToken);
}
#After
public void cleanUp() {
SecurityContextHolder.clearContext();
}
#Test
public void add(){
Candidate candidate = new Candidate();
candidate.setName("testUser");
candidate.setPhone("88888");
candidateService.add(candidate);
List<Candidate> candidates = candidateService.findByName(candidate.getName());
Assert.assertNotNull(candidates);
Assert.assertEquals("88888", candidates.get(0).getPhone());
}
}
test is green but after executing I don't see data in my database.
Can you explain me why and how to fix it?
UPDATE
configuration:
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Менеджер транзакций -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
above your test class will not affect to database.
set or add defaultRollback = false to see data persisted in table.
I think you should add TransactionConfiguration annotation with param defaultRollback = false
After completion of test method the changes are rolled back. Test method database changes are reverted and you can do the other test with new data.
You no need to worry about the model object with same id in different test cases.
If you need common data you can do with in setup() method that changes also not saved in the database.
Before executing test methods the setup() method will be called. if you have 3 test method then 3 times setup() method will be called.
sorry for my bad English.......
I have a problem to select the correct spring bean that should get injected.
I need a way to tell the spring container what bean to inject depeding on the call to a previous class. I do all the spring bean wiring in xml.
My question: is this possible and if it is any reference on an implementation?
I have created some sample code to illustrate what i´m trying to accomplish. Feel free to change it so that it will work to get the correct ReportHeader bean injected depending on the selected reportType during runtime.
public enum ReportType{
Credit,
Annul
}
public class ReportService {
private ReportHeaderService reportHeaderService;
private ReportType reportType;
public ReportService (){}
public setReportType(ReportType reportType){
this.reportType = reportType;
}
public void setReportHeaderService(ReportHeaderService reportHeaderService){
this.reportHeaderService = reportHeaderService;
}
private void generateHeader(){
//i would like to call my service like this and have the correct bean injected to ReportHeader.
reportHeaderService.generateHeader(reportType)
}
}
public class ReportHeaderService {
private ReportHeader reportHeader;
//this will call the injected bean that needs to be selected accoring to the ReportType
public void generateHeader(ReportType type){
reportHeader.createHeader();
}
}
public interface ReportHeader{
public void createHeader();
}
public class CreditReportHeader implements ReportHeader{
public void createHeader(){
..dostuff();
}
}
public class AnnulReportHeader implements ReportHeader{
public void createHeader(){
..dostuff();
}
}
Consider injecting a Map<ReportType, ReportHeader> to ReportHeaderService, so that generateHeader works as:
public class ReportHeaderService {
private Map<ReportType, ReportHeader> reportHeaderMap;
public void generateHeader(ReportType type){
ReportHeader reportHeader = reportHeaderMap.get(type);
if (reportHeader != null) {
reportHeader.createHeader();
}
}
}
You can define a ReportHeaderFactory to get the ReportHeader according to ReportType:
public class ReportHeaderFactory {
private CreditReportHeader creditReportHeader;
private AnnulReportHeader annulReportHeader;
public ReportHeader getReportHeader(ReportType reportType) {
switch (reportType) {
case Credit:
return creditReportHeader;
case Annul:
return annulReportHeader;
default:
throw new IllegalArgumentException("No Such Header");
}
}
}
Re-define the ReportHeaderService with an instance of ReportHeaderFactory:
public class ReportHeaderService {
//private ReportHeader reportHeader;
private ReportHeaderFactory headerFactory;
//this will call the injected bean that needs to be selected accoring to the ReportType
public void generateHeader(ReportType type){
//reportHeader.createHeader();
headerFactory.getReportHeader(type);
}
}
As you are doing all the spring bean wiring in xml, you just need to make below entries in the config file:
<bean id="ReportHeaderService" class="x.y.ReportHeaderService">
<property name="headerFactory" ref="headerFactory" />
</bean>
<bean id="headerFactory" class="x.y.ReportHeaderFactory">
<property name="creditReportHeader" ref="creditReportHeader" />
<property name="annulReportHeader" ref="annulReportHeader" />
</bean>
<bean id="creditReportHeader" class="x.y.CreditReportHeaderImpl" />
<bean id="annulReportHeader" class="x.y.AnnulReportHeaderImpl" />
Currently I use #ModelAttribute to set global variables (e.g. tweets for the footer) in my #Controller:
public #Controller class MainController {
public #ModelAttribute void global(ModelMap map) {
map.addAttribute("tweets", /*...*/null);
}
}
But they're logically gone when creating another Controller to keep things clean and separated:
public #Controller class GalleryController {
// ...
}
What's the best practice to set global variables Controller wide?
If you want to put some data to every page it is easy to use interceptor:
public class PagePopulationInterceptor extends HandlerInterceptorAdapter {
#Autowired
private UserService userService;
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if(modelAndView != null) {
User user = userService.findOne(request);
modelAndView.addObject("myUserProfile", user);
}
}
}
To make this work also declare interceptor in webmvc-config.xml (spring configuration for webapp):
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.yourcompany.yourapp.util.PagePopulationInterceptor" />
</mvc:interceptor>
<!-- other interceptors (locale, theme and so on) -->
</mvc:interceptors>
you can extend HandlerInterceptorAdapter and add common modelAttributes thr