我正在尝试运行一个我从Google获取的示例,看看我是否可以从App Engine访问Google+。我将以下文件添加到我的项目中并设置了servlet映射,以便它们在预期的路径上可用。我将它部署到app引擎并尝试访问应用程序。转到https://mydomain.appspot.com/会给我错误:NOT_FOUND。访问sampleservlet的url给了我下面提到的例外。样本取自https://github.com/google/google-api-java-client-samples/tree/master/plus-appengine-sample
这些示例可能不是最新的,但它们是我可以从Google找到的最新版本。任何有关我应该做些什么的线索都会有所帮助。
我的课程如下:
BasicServlet:
public class PlusBasicServlet extends HttpServlet {
/**
* Enter your API key here from https://code.google.com/apis/console/?api=plus under "API Access".
*/
private static final String API_KEY = "AIzaSyB9NEc2yQRisoj-rIqgg35yeZXReASMRCI";
private static final long serialVersionUID = 1;
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
HttpTransport httpTransport = new UrlFetchTransport();
JsonFactory jsonFactory = new JacksonFactory();
Plus plus = new Plus.Builder(httpTransport, jsonFactory, null).setApplicationName("")
.setGoogleClientRequestInitializer(new PlusRequestInitializer(API_KEY)).build();
ActivityFeed myActivityFeed = plus.activities().search("Google").execute();
List<Activity> myActivities = myActivityFeed.getItems();
resp.setContentType("text/html");
resp.setStatus(200);
Writer writer = resp.getWriter();
writer.write("<ul>");
for (Activity a : myActivities) {
writer.write("<li>" + a.getTitle() + "</li>");
}
writer.write("</ul>");
}
}
回调:
public class PlusSampleAuthCallbackServlet
extends AbstractAppEngineAuthorizationCodeCallbackServlet {
private static final long serialVersionUID = 1L;
@Override
protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
throws ServletException, IOException {
resp.sendRedirect(Utils.MAIN_SERVLET_PATH);
}
@Override
protected void onError(
HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
throws ServletException, IOException {
String nickname = UserServiceFactory.getUserService().getCurrentUser().getNickname();
resp.getWriter().print("<h3>Hey " + nickname + ", why don't you want to play with me?</h1>");
resp.setStatus(200);
resp.addHeader("Content-Type", "text/html");
return;
}
@Override
protected AuthorizationCodeFlow initializeFlow() throws ServletException, IOException {
return Utils.initializeFlow();
}
@Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
return Utils.getRedirectUri(req);
}
}
的Util:
class Utils {
/**
* Global instance of the {@link DataStoreFactory}. The best practice is to make it a single
* globally shared instance across your application.
*/
private static final AppEngineDataStoreFactory DATA_STORE_FACTORY =
AppEngineDataStoreFactory.getDefaultInstance();
private static GoogleClientSecrets clientSecrets = null;
private static final Set<String> SCOPES = Collections.singleton(PlusScopes.PLUS_ME);
static final String MAIN_SERVLET_PATH = "/plussampleservlet";
static final String AUTH_CALLBACK_SERVLET_PATH = "/oauth2callback";
static final UrlFetchTransport HTTP_TRANSPORT = new UrlFetchTransport();
static final JacksonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static GoogleClientSecrets getClientSecrets() throws IOException {
if (clientSecrets == null) {
clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(Utils.class.getResourceAsStream("/plus_secret.json")));
Preconditions.checkArgument(!clientSecrets.getDetails().getClientId().startsWith("Enter ")
&& !clientSecrets.getDetails().getClientSecret().startsWith("Enter "),
"Download client_secrets.json file from https://code.google.com/apis/console/?api=plus "
+ "into plus-appengine-sample/src/main/resources/client_secrets.json");
}
return clientSecrets;
}
static GoogleAuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, getClientSecrets(), SCOPES).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
static String getRedirectUri(HttpServletRequest req) {
GenericUrl requestUrl = new GenericUrl(req.getRequestURL().toString());
requestUrl.setRawPath(AUTH_CALLBACK_SERVLET_PATH);
return requestUrl.build();
}
}
SampleServlet:
public class PlusSampleServlet extends AbstractAppEngineAuthorizationCodeServlet {
private static final long serialVersionUID = 1L;
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
// Get the stored credentials using the Authorization Flow
AuthorizationCodeFlow authFlow = initializeFlow();
Credential credential = authFlow.loadCredential(getUserId(req));
// Build the Plus object using the credentials
Plus plus = new Plus.Builder(
Utils.HTTP_TRANSPORT, Utils.JSON_FACTORY, credential).setApplicationName("").build();
// Make the API call
Person profile = plus.people().get("me").execute();
// Send the results as the response
PrintWriter respWriter = resp.getWriter();
resp.setStatus(200);
resp.setContentType("text/html");
respWriter.println("<img src='" + profile.getImage().getUrl() + "'>");
respWriter.println("<a href='" + profile.getUrl() + "'>" + profile.getDisplayName() + "</a>");
}
@Override
protected AuthorizationCodeFlow initializeFlow() throws ServletException, IOException {
return Utils.initializeFlow();
}
@Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
return Utils.getRedirectUri(req);
}
}
访问示例servlet时出现异常:
Uncaught exception from servlet
java.lang.NullPointerException
at com.google.api.client.extensions.appengine.auth.oauth2.AbstractAppEngineAuthorizationCodeServlet.getUserId(AbstractAppEngineAuthorizationCodeServlet.java:92)
at com.google.api.client.extensions.servlet.auth.oauth2.AbstractAuthorizationCodeServlet.service(AbstractAuthorizationCodeServlet.java:122)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
答案 0 :(得分:0)
必须在web.xml下添加标签:
<security-constraint>
<web-resource-collection>
<web-resource-name>any</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>