问题
I am having trouble implementing a Login interface like the example Simple CRUD Web Application with JSF 2.1, PrimeFaces 3.5, EJB 3.1, JPA (ORM) / EclipseLink, JAAS , MySQL On TomEE's mailing list, I have been told that the LoginController.java I am using tries to inject Logger, but Logger injection is not managed by CDI. I have been told to use a producer instead. Not knowing what it is, I searched on the internet and I found this example But I am still not confortable with it, so please explain what I have to modify to implement producer for logger.
LoginController.java
package controller;
import util.DateUtility;
import java.io.IOException;
import java.io.Serializable;
import java.security.Principal;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* Login Controller class allows only authenticated users to log in to the web
* application.
*
* @author Emre Simtay <emre@simtay.com>
*/
@Named
@SessionScoped
public class LoginController implements Serializable {
@Inject
private transient Logger logger;
private String username;
private String password;
/**
* Creates a new instance of LoginController
*/
public LoginController() {
System.out.println("test");
}
// Getters and Setters
/**
* @return username
*/
public String getUsername() {
return username;
}
/**
*
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
*
* @return password
*/
public String getPassword() {
return password;
}
/**
*
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Listen for button clicks on the #{loginController.login} action,
* validates the username and password entered by the user and navigates to
* the appropriate page.
*
* @param actionEvent
*/
public void login(ActionEvent actionEvent) {
System.out.println("CONSOLE PRINT TEST");
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try {
String navigateString = "";
// Checks if username and password are valid if not throws a ServletException
request.login(username, password);
// gets the user principle and navigates to the appropriate page
Principal principal = request.getUserPrincipal();
if (request.isUserInRole("Administrator")) {
navigateString = "/admin/AdminHome.xhtml";
} else if (request.isUserInRole("Manager")) {
navigateString = "/manager/ManagerHome.xhtml";
} else if (request.isUserInRole("User")) {
navigateString = "/user/UserHome.xhtml";
}
try {
logger.log(Level.INFO, "User ({0}) loging in #" + DateUtility.getCurrentDateTime(), request.getUserPrincipal().getName());
context.getExternalContext().redirect(request.getContextPath() + navigateString);
} catch (IOException ex) {
logger.log(Level.SEVERE, "IOException, Login Controller" + "Username : " + principal.getName(), ex);
context.addMessage(null, new FacesMessage("Error!", "Exception occured"));
}
} catch (ServletException e) {
logger.log(Level.SEVERE, e.toString());
context.addMessage(null, new FacesMessage("Error!", "The username or password you provided does not match our records."));
}
}
/**
* Listen for logout button clicks on the #{loginController.logout} action
* and navigates to login screen.
*/
public void logout() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
logger.log(Level.INFO, "User ({0}) loging out #" + DateUtility.getCurrentDateTime(), request.getUserPrincipal().getName());
if (session != null) {
session.invalidate();
}
FacesContext.getCurrentInstance().getApplication().getNavigationHandler().handleNavigation(FacesContext.getCurrentInstance(), null, "/Login.xhtml?faces-redirect=true");
}
}
回答1:
When you use @Inject
, CDI tries to create an instance of the requested type for you. The simplest solution: It calls the default constructor and returns that instance.
Problem with java.util.logging.Logger
: it has no visible default constructor. So you have to tell CDI how to satisfy the dependency by adding a Producer to your classpath. Although using the weld-logger @JohnAment suggested would be my prefered solution as well, given your current state of knowledge its probably best for you, if you start by adding your own producer.
So beside your controller, create a new Class (add package, import, ... yourself)
public class LoggerProducer {
@Produces
public Logger getLogger(InjectionPoint p) {
return Logger.getLogger(p.getClass().getCanonicalName());
}
}
This tells the CDI container: whenever you need to inject a java.util.logging.Logger
, use this method to create one by taking the fqn name of the class where that logger reference is needed.
This should solve your problem. Once you got the idea, think if you really want/need to use java.util.logging or if you want to switch to slf4j. In that case, modify your controller imports, remove the LoggerProducer you just wrote and import the weld-logger jar to your deployment instead.
回答2:
They are correct, there is no standard injection of loggers available. You can look at this example, from Weld, on how to inject their customer logger. Please feel free to modify it to use java.util.logging.
http://grepcode.com/file/repo1.maven.org/maven2/org.jboss.weld/weld-logger/1.0.0-CR1/org/jboss/weld/log/LoggerProducer.java
来源:https://stackoverflow.com/questions/21076836/logger-convert-from-inject-to-producer