我已经在GWT + Spring Boot中创建了一个应用程序,当我尝试使用@Autowired
时-得到NullPointerException
。显然@Autowired
不起作用,并且没有在正确的位置插入Bean。我该如何解决这种情况?
调度传入的RPC调用时发生异常
com.google.gwt.user.server.rpc.UnexpectedException:服务方法 '公共抽象java.util.List com.myGWT.springbootapp.client.UserService.list()引发了意外 异常:java.lang.NullPointerException
文件web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>userService</servlet-name>
<servlet-class>com.myGWT.springbootapp.server.UserServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>userService</servlet-name>
<url-pattern>/gwtApp/service</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>GWTApp.html</welcome-file>
</welcome-file-list>
</web-app>
pom.xml
<name>spring-boot-app</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<gwt.version>2.7.0</gwt.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<!-- GWT -->
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>${gwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-codeserver</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>${gwt.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>apache-jsp</artifactId>
<groupId>org.eclipse.jetty</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwt.version}</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>target</directory>
</fileset>
<fileset>
<directory>builds</directory>
<includes>
<include>**/*.*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>deploy</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<id>deploy</id>
<phase>deploy</phase>
<goals><goal>deploy</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
文件UserServiceImpl.java
package com.myGWT.springbootapp.server;
import com.myGWT.springbootapp.client.UserService;
import com.myGWT.springbootapp.entities.User;
import com.myGWT.springbootapp.repositories.UserRepository;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl extends RemoteServiceServlet implements UserService {
AnnotationConfigWebApplicationContext();
@Autowired
private UserRepository repository ;
@Override
public List<User> list() {
return repository.findAll();
}
}
文件UserRepository.java
package com.myGWT.springbootapp.repositories;
import com.myGWT.springbootapp.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
文件UserService.java
package com.myGWT.springbootapp.client;
import com.myGWT.springbootapp.entities.User;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import java.util.List;
@RemoteServiceRelativePath("service")
public interface UserService extends RemoteService {
List<User> list();
}
文件GWTApp.java
package com.myGWT.springbootapp.client;
import com.myGWT.springbootapp.entities.User;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.view.client.ListDataProvider;
import java.util.List;
public class GWTApp implements EntryPoint {
private UserServiceAsync userService = GWT.create(UserService.class);
private ListDataProvider<User> createTable (CellTable<User> table){
TextColumn<User> idColumn =new TextColumn<User>() {
@Override
public String getValue(User object) {
return object.getId().toString();
}
};
TextColumn<User> loginColumn =new TextColumn<User>() {
@Override
public String getValue(User object) {
return object.getLogin();
}
};
table.addColumn(idColumn, "Id");
table.addColumn(loginColumn, "Login");
final ListDataProvider<User> dataProvider = new ListDataProvider<>();
dataProvider.addDataDisplay(table);
this.userService.list(new AsyncCallback<List<User>>() {
@Override
public void onFailure(Throwable caught) {
Window.alert("Error: " + caught.getMessage());
}
@Override
public void onSuccess(List<User> result) {
dataProvider.getList().addAll(result);
}
});
return dataProvider;
}
public void onModuleLoad() {
CellTable<User> table = new CellTable<>();
ListDataProvider<User> dataProvider = createTable(table);
RootPanel.get().add(table);
}
}
项目的目录结构
答案 0 :(得分:1)
简短的答案是:Spring并未实例化您的GWT服务;因此它无法自动将任何东西连接到其中。
Jetty容器实际上负责创建和映射UserServiceImpl
的实例。这就是您的web.xml
所描述的。
您的@Service
注解确实在Spring上下文中创建了一个Servlet实例,正如您所期望的那样,但Jetty并不知道。历史上,我已从基于RemoteServiceServlet
的服务中删除了@Service批注,并添加了以下方法来提供@Autowire
支持:
public class UserServiceImpl extends RemoteServiceServlet implements UserService {
...
@Override
public void init() throws ServletException {
super.init();
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
}
...
}
来自SpringBeanAutowiringSupport
javadoc:
根据存储在ServletContext中的当前根Web应用程序上下文,对给定目标对象进行@Autowired注入。
在Servlet创建和繁荣期间,Jetty会调用init()
,真是令人难以置信。这是很棘手的事情,因为它桥接了两个不相关的流程,但目前在生产中对我有用。
使用兼容Servlet 3.0+的容器,您可能可以找到一种方法来使用WebApplicationInitializer
(javadoc)来AnnotationConfigWebApplicationContext
(javadoc)来启动Spring上下文。映射到servlet,这将允许您从那里使用实例(这取代了web.xml
)。
编辑:
由于您使用的是Spring Boot,因此可以看一下该线程,该线程显示了如何通过ServletRegistrationBean
:How can I register a secondary servlet with Spring Boot?映射servlet(请参阅checketts的答案)