我有一个@sessionscoped bean,一个带有@stateless注释和@inject the bean和@ejb我的EJB的Restful Jersey服务。
当我试图从浏览器的URL调用rest web服务时,服务会注入@inject UserBean。但是当我试图从@SessionScoped UserBean中的代码调用web服务时,它不会被注入。
豆子:
@SessionScoped
@Named("userBean")
public class UserBean implements Serializable {
@EJB
private UserEJB userEJB;
private User user = new User();
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
private String newStatusContent;
public String getNewStatusContent() {
return newStatusContent;
}
public void setNewStatusContent(String content) {
this.newStatusContent = content;
}
public void publishStatus() {
if (newStatusContent != null && newStatusContent.trim().isEmpty() == false) {
//Maybe a way to set manualy the user property of this bean here?
Client client = ClientBuilder.newClient();
Response response = client.target("http://localhost:8080/services/posts/status")
.queryParam("content", newStatusContent)
.request(MediaType.APPLICATION_JSON).get();
newStatusContent = "";
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request
= (HttpServletRequest) context.getExternalContext().getRequest();
if (request.getRequestURI().equals("/index/profile/profile.xhtml") && request.getParameter("prettyname") != null && request.getParameter("prettyname").equals(user.getPrettyname())) {
}
if (response.getStatus() == 200) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Δημοσίευση", "Η νέα κατάσταση δημοσιεύτηκε επιτυχώς."));
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Δημοσίευση", "Συγγνώμη, κάτι πήγε στραβά με την νέα κατάσταση :("));
}
}
}
public String login() throws ServletException {
User authenticatedUser;
if (userEJB.mailExists(user)) {
if ((authenticatedUser = userEJB.authenticate(user)) != null) {
user = authenticatedUser;
//and store the api key for rest api
// userEJB.storeApiKey(user.getUserId());
} else {
FacesContext.getCurrentInstance().addMessage("mail", new FacesMessage("Wrong password for this e-mail"));
return "";
}
} else {
user = userEJB.create(user);
}
if (getPrevURI().isEmpty() == false) {
return getPrevURI();
} else {
return "/index/index.xhtml?faces-redirect=true";
}
}
}
@ApplicationPath("/services/*")
public class RestApplication extends javax.ws.rs.core.Application{
@Override
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>(Arrays.asList(
UserService.class,
MessageService.class, PostService.class));
}
}
@Path("/posts")
@Stateless
public class PostService {
@EJB
private PostEJB postEJB;
@Inject
UserBean userBean;
@Path("/status")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response publishStatus(@QueryParam("content") String content) {
if (content.isEmpty() || userBean.getUser().getUserId() == null) {
System.out.println("null user id or content but?" + content);
return Response.status(Response.Status.BAD_REQUEST).build();
}
Post postStatus = new Post();
postStatus.setContent(content.trim());
postStatus.setPublisher(userBean.getUser());
postStatus.setPublisherUserId(userBean.getUser().getUserId());
postEJB.create(postStatus);
System.out.println("post id : "+postStatus.getPostId());
PostStatus status = new PostStatus(postStatus.getPostId());
status.setReceiver(userBean.getUser());
status.setReceiverId(userBean.getUser().getUserId());
postEJB.postStatus(status);
return Response.status(Response.Status.OK).build();
}
//*this is not the problem I tried to remove and still doesn't worked*
@PreDestroy
public void destruct() {
postEJB.destruct();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans 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/beans_1_1.xsd"
bean-discovery-mode="all"
>
</beans>
http://localhost:8080/services/posts/status?content=Test status
我使用的是Glassfish 4.1、JDK 8.20、Jersey 2.10(模块Glassfish)。
我做错了什么?为什么要处理浏览器的url,而不是从代码调用客户端?
----使用另一种方式----使用保存在加密Cookie(用于浏览器的/JS调用)和加密会话中的“API密钥”
另一种方式来进行安全身份验证,但这并不是我想要的:
ApiAuthenticator服务筛选器:
public class ApiAuthenticator implements ClientRequestFilter {
private static final StandardPBEStringEncryptor encryptor;
static {
encryptor = new StandardPBEStringEncryptor();
encryptor.setPassword("jasypt");
}
public static String encrypt(String theString) {
return encryptor.encrypt(theString);
}
public static String decrypt(String encryptedString) {
return encryptor.decrypt(encryptedString);
}
private final String apikey;
public ApiAuthenticator(String apikey) {
this.apikey = apikey;
}
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
//requestContext.getCookies().putIfAbsent("apikey", new Cookie("apikey", apikey));
requestContext.getHeaders().add("apikey", encrypt(apikey));
}
}
PostService内编辑的publishStatus方法:
@Path("/status")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response publishStatus(@QueryParam("content") String content, @Context HttpHeaders headers) {
String apikey = headers.getHeaderString("apikey");
if (apikey == null) {
apikey = headers.getCookies().get("apikey").getValue();
}
if (content.isEmpty() || apikey == null) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
User user = userEJB.findByApiKey(ApiAuthenticator.decrypt(apikey));
Post postStatus = new Post();
postStatus.setContent(content.trim());
postStatus.setPublisher(user);
postStatus.setPublisherUserId(user.getUserId());
postEJB.create(postStatus);
PostStatus status = new PostStatus(postStatus.getPostId());
status.setReceiver(user);
status.setReceiverId(user.getUserId());
postEJB.postStatus(status);
return Response.status(Response.Status.OK).build();
}
Client client = ClientBuilder.newClient();
Response response = client.target("http://localhost:8080/services/posts/status")
.queryParam("content", newStatusContent)
.register(new ApiAuthenticator(apiEJB.getApiKey(user.getUserId()).getApiKey()))
.request(MediaType.APPLICATION_JSON).get();
用户成功登录后在UserBean上编辑的登录方法:
((HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse())
.addCookie(new Cookie("apikey", ApiAuthenticator.encrypt(apiEJB.storeApiKey(user.getUserId()).getApiKey())));
RestApplication.java:
@ApplicationPath("/services/*")
public class RestApplication extends javax.ws.rs.core.Application{
@Override
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>(Arrays.asList(
ApiAuthenticator.class ,
UserService.class,
MessageService.class, PostService.class));
}
}
解决方案是@将PostService注入UserBean
@Inject PostService postService;
postService.publishStatus(newStatusContent);
@ServerEndpoint(value = "/websocket", encoders = {MessageEncoder.class},
decoders = {MessageDecoder.class}, configurator = GetHttpSessionConfigurator.class)
public class ChatServerEndPoint {
@PersistenceContext(unitName = "CosmosDBPeristenceUnit")
private EntityManager em;
private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
@Inject
private MessageService messageService;
//private Session session;
private int thisUserId;
private User thisUser;
@OnOpen
public void onOpen(Session thisSession, EndpointConfig config) throws IOException, EncodeException {
thisUserId = (int) config.getUserProperties().get("userId");
thisUser = em.find(User.class, thisUserId);
thisSession.getUserProperties().put("userId", thisUserId);
Iterator<Session> it = peers.iterator();
while (it.hasNext()) {
Session session = it.next();
int userId = (int) session.getUserProperties().get("userId");
thisSession.getBasicRemote().sendObject(new UserStatusMessage(em.find(User.class, userId), true));
session.getBasicRemote().sendObject(new UserStatusMessage(thisUser, true));
}
peers.add(thisSession);
}
/* we don't want @stateless problems with chat info except message, I will do it with rest public */
@OnMessage
public void onMessage(WebsocketMessage message) {
try {
Iterator<Session> it = peers.iterator();
if (message instanceof ChatMessage) {
ChatMessage msg = (ChatMessage) message;
msg.setSender(thisUser);
boolean otherUserIsOnline = false;
while (it.hasNext()) {
Session receiver = it.next();
if ((int) receiver.getUserProperties().get("userId") == msg.getReceiver_userId()) {
receiver.getBasicRemote().sendObject(msg);
otherUserIsOnline = true;
break;
}
}
if (otherUserIsOnline == false) {
//save the message to database via rest
messageService.addMessage(msg.getReceiver_userId(), msg.getMessage());
}
} else {
while (it.hasNext()) {
Session receiver = it.next();
receiver.getBasicRemote().sendObject(message);
}
}
} catch (IOException | EncodeException ex) {
System.out.println("Exception on endpoint: " + ex.getMessage());
}
}
@OnClose
public void onClose(Session session) throws IOException, EncodeException {
peers.remove(session);
Iterator<Session> it = peers.iterator();
while (it.hasNext()) {
Session otherSession = it.next();
otherSession.getBasicRemote().sendObject(new UserStatusMessage(thisUser, false));
}
}
@OnError
public void onError(Throwable t) {
t.printStackTrace();
}
}
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
HttpSession ses = (HttpSession) request.getHttpSession();
config.getUserProperties().put("userId", ses.getAttribute("userId"));
}
}
java:
@Stateless
@Path("/messages")
public class MessageService {
@EJB
UserEJB userEJB;
@EJB
ConversationEJB convEJB;
@Inject
UserBean userBean;
@Path("/{otherUserId}")
@GET
@Produces("application/json; charset=UTF-8")
public List<Message> findConversation(@PathParam("otherUserId") int otherUserId) {
User otherUser = userEJB.findById(otherUserId);
return convEJB.findConversation(userBean.getUser(), otherUser);
}
@Path("/{receiverUserId}")
@POST
@Produces("application/json; charset=UTF-8")
public Message addMessage(@PathParam("receiverUserId") int receiverUserId, @QueryParam("body") String body) {
return convEJB.addMessage(userBean.getUser(), userEJB.findById(receiverUserId), body);
}
@Path("/{messageId}")
@DELETE
public void removeMessage(@PathParam("messageId") int messageId) {
convEJB.removeMessage(messageId);
}
@Path("/{userId}/{otherUserId}")
@DELETE
public void clearConversation(@PathParam("userId") int userId, @PathParam("otherUserId") int otherUserId) {
convEJB.clearConversation(userEJB.findById(userId), userEJB.findById(otherUserId));
}
}
提前感谢!
由于我不知道应用程序的确切流程,这可能是错误的,但这里是我的假设:
您的userBean是会话范围,它保存用户数据。不知何故,在你的应用程序中,它可能是初始化的。
因此,一旦您从浏览器调用服务,它就会发送会话cookie来正确定位会话数据。
但是当您从代码中调用服务时,它不会传递那个会话cookie,所以在服务器端它会创建全新的会话,从而创建具有空用户数据的新userBean。这就是为什么用户ID为空。Bean本身被注入,否则这里将有空指针:
userBean.getUser().getUserId() // as userBean would be null
这是我的代码,我不知道为什么我的bean没有被注入,它在构造函数中总是空的 下面是我的配置类: 我的堆栈跟踪 启动ApplicationContext时出错。若要显示自动配置报告,请在启用“debug”的情况下重新运行应用程序。11:55:29.139[restartedMain]错误O.S.Boot.SpringApplication-应用程序启动失败org.SpringFramework.Be
例如,如果几个资源endpoint需要访问某个消息总线来处理请求,该怎么办?当然,当服务类本身不是资源但被资源使用时,有一些方法可以注册一个单例服务类并将其注入到资源中。 我看到的提供程序或自定义HK2绑定的所有示例都引用了资源。 我发现的最接近我所要找的是这个问题: 使用内置的Jersey依赖注入在Jersey 2中创建一个简单的单例类会遇到麻烦 请注意,编程方式将是最有用的,我没有使用xml文
所以我有一个类需要测试。我们把它叫做ClassToTest。它有两个Dao对象作为字段。 正如您所看到的,ClassToTest不包含任何构造函数或setter,我正在使用spring自动关联字段。 现在,我有了一个具有classToTest所需的所有依赖项的基本测试类: 并且testClass扩展了这个BaseTest类: 这将导致保存时出现空指针异常。但是,如果我将设置方法更改为: 考试通过了
将EntityManager注入资源可以工作,但不能注入Callable。在这里,EntityManager保持。 请告知代码保存在这里是否比保存在GitHub上更好。
我们可以通过 实现创建JAX-RS示例。 为此,需要加载 jersey相关jar文件或使用Maven框架。 在这个例子中,我们使用jersey jar文件来实现JAX-RS jersey示例。 Jersey Jar文件下载网址:https://jersey.github.io/download.html 打开Eclipse,创建一个Web工程: restfuljersey,如下图所示 - JAX-
我正在学习Jersey/JAX-RS,需要一些ExceptionMapper方面的帮助。 我有一个UserFacade类、AbstractFacade类和User类本身,它们都是非常标准的,主要是通过在NetBeans中创建一个新的Web服务RestFUL项目生成的。我的问题是,我想现在开始捕捉错误,比如“唯一约束违反”错误。我想我需要实现一个异常映射器...我的门面有以下内容: 这是我得到的错误