我正在尝试在我的项目中使用Amazon SNS servlet。但是,Tomcat给了我这样的错误:
Nov 26, 2015 1:28:49 PM org.apache.catalina.startup.Catalina start
SEVERE: The required Server component failed to start so Tomcat is unable to start.
org.apache.catalina.LifecycleException: Failed to start component [StandardServer[8005]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.startup.Catalina.start(Catalina.java:689)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:321)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:455)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardService[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:739)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 7 more
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:443)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 9 more
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1130)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:300)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
... 11 more
我已经阅读了很多类似问题的解决方案,例如:
我们不能在Web-INF / lib中有重复的jar,尤其是servlet.jar,因为它可能与Tomcat的配置冲突。
检查.classpath或web.xml文件。
等。
但是在我尝试了所有的东西后,它仍然没有用。
这是我的类路径:
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="con" path="com.amazonaws.eclipse.sdk.AWS_JAVA_SDK"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/com.fasterxml.jackson.core.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/commons-fileupload-1.3.1.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/jackson-annotations-2.1.2.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/json-simple-1.1.1.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/mysql-connector-java-5.1.37-bin.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/org.json-20120521.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/tomcat-juli.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/twitter4j-async-4.0.2.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/twitter4j-core-4.0.2.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/twitter4j-examples-4.0.2.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/twitter4j-media-support-4.0.2.jar"/>
<classpathentry kind="lib" path="/Users/Liang/Documents/workspace/tweetMap/WebContent/WEB-INF/lib/twitter4j-stream-4.0.2.jar"/>
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/Apache Tomcat v7.0"/>
<classpathentry kind="output" path="build/classes"/>
</classpath>
这是我的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>tweetMap</display-name>
<welcome-file-list>
<welcome-file>GoogleMap.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>SNSServlet</servlet-name>
<servlet-class>SNSServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SNSServlet</servlet-name>
<url-pattern>/SNSServlet</url-pattern>
</servlet-mapping>
</web-app>
这是我的SNSServlet.java:
public class SNSServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public SNSServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SecurityException{
AWSCredentials credentials = new BasicAWSCredentials("xx","xxx");
DatabaseHelper db = new DatabaseHelper().withCredentials(credentials);
//Get the message type header.
String messagetype = request.getHeader("x-amz-sns-message-type");
//If message doesn't have the message type header, don't process it.
if (messagetype == null)
return;
// Parse the JSON message in the message body
// and hydrate a Message object with its contents
// so that we have easy access to the name/value pairs
// from the JSON message.
Scanner scan = new Scanner(request.getInputStream());
StringBuilder builder = new StringBuilder();
while (scan.hasNextLine()) {
builder.append(scan.nextLine());
}
SNSMessage msg = readMessageFromJson(builder.toString());
// The signature is based on SignatureVersion 1.
// If the sig version is something other than 1,
// throw an exception.
if (msg.getSignatureVersion().equals("1")) {
// Check the signature and throw an exception if the signature verification fails.
if (isMessageSignatureValid(msg))
System.out.println(">>Signature verification succeeded");
else {
System.out.println(">>Signature verification failed");
throw new SecurityException("Signature verification failed.");
}
}
else {
System.out.println(">>Unexpected signature version. Unable to verify signature.");
throw new SecurityException("Unexpected signature version. Unable to verify signature.");
}
// Process the message based on type.
if (messagetype.equals("Notification")) {
//TODO: Do something with the Message and Subject.
//Just log the subject (if it exists) and the message.
String logMsgAndSubject = ">>Notification received from topic " + msg.getTopicArn();
if (msg.getSubject() != null)
logMsgAndSubject += " Subject: " + msg.getSubject();
logMsgAndSubject += " Message: " + msg.getMessage();
String mes = msg.getMessage();
System.out.println(logMsgAndSubject);
}
else if (messagetype.equals("SubscriptionConfirmation"))
{
//TODO: You should make sure that this subscription is from the topic you expect. Compare topicARN to your list of topics
//that you want to enable to add this endpoint as a subscription.
//Confirm the subscription by going to the subscribeURL location
//and capture the return value (XML message body as a string)
Scanner sc = new Scanner(new URL(msg.getSubscribeURL()).openStream());
StringBuilder sb = new StringBuilder();
while (sc.hasNextLine()) {
sb.append(sc.nextLine());
}
System.out.println(">>Subscription confirmation (" + msg.getSubscribeURL() +") Return value: " + sb.toString());
//TODO: Process the return value to ensure the endpoint is subscribed.
SNSHelper.INSTANCE.confirmTopicSubmission(msg);
}
else if (messagetype.equals("UnsubscribeConfirmation")) {
//TODO: Handle UnsubscribeConfirmation message.
//For example, take action if unsubscribing should not have occurred.
//You can read the SubscribeURL from this message and
//re-subscribe the endpoint.
System.out.println(">>Unsubscribe confirmation: " + msg.getMessage());
}
else {
//TODO: Handle unknown message type.
System.out.println(">>Unknown message type.");
}
System.out.println(">>Done processing message: " + msg.getMessageId());
}
private boolean isMessageSignatureValid(SNSMessage msg) {
try {
URL url = new URL(msg.getSigningCertUrl());
InputStream inStream = url.openStream();
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
inStream.close();
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(cert.getPublicKey());
sig.update(getMessageBytesToSign(msg));
return sig.verify(Base64.decodeBase64(msg.getSignature().getBytes()));
}
catch (Exception e) {
throw new SecurityException("Verify method failed.", e);
}
}
private byte[] getMessageBytesToSign(SNSMessage msg) {
byte [] bytesToSign = null;
if (msg.getType().equals("Notification"))
bytesToSign = buildNotificationStringToSign(msg).getBytes();
else if (msg.getType().equals("SubscriptionConfirmation") || msg.getType().equals("UnsubscribeConfirmation"))
bytesToSign = buildSubscriptionStringToSign(msg).getBytes();
return bytesToSign;
}
//Build the string to sign for Notification messages.
private static String buildNotificationStringToSign( SNSMessage msg) {
String stringToSign = null;
//Build the string to sign from the values in the message.
//Name and values separated by newline characters
//The name value pairs are sorted by name
//in byte sort order.
stringToSign = "Message\n";
stringToSign += msg.getMessage() + "\n";
stringToSign += "MessageId\n";
stringToSign += msg.getMessageId() + "\n";
if (msg.getSubject() != null) {
stringToSign += "Subject\n";
stringToSign += msg.getSubject() + "\n";
}
stringToSign += "Timestamp\n";
stringToSign += msg.getTimestamp() + "\n";
stringToSign += "TopicArn\n";
stringToSign += msg.getTopicArn() + "\n";
stringToSign += "Type\n";
stringToSign += msg.getType() + "\n";
return stringToSign;
}
//
// //Build the string to sign for SubscriptionConfirmation
// //and UnsubscribeConfirmation messages.
private static String buildSubscriptionStringToSign(SNSMessage msg) {
String stringToSign = null;
//Build the string to sign from the values in the message.
//Name and values separated by newline characters
//The name value pairs are sorted by name
//in byte sort order.
stringToSign = "Message\n";
stringToSign += msg.getMessage() + "\n";
stringToSign += "MessageId\n";
stringToSign += msg.getMessageId() + "\n";
stringToSign += "SubscribeURL\n";
stringToSign += msg.getSubscribeURL() + "\n";
stringToSign += "Timestamp\n";
stringToSign += msg.getTimestamp() + "\n";
stringToSign += "Token\n";
stringToSign += msg.getToken() + "\n";
stringToSign += "TopicArn\n";
stringToSign += msg.getTopicArn() + "\n";
stringToSign += "Type\n";
stringToSign += msg.getType() + "\n";
return stringToSign;
}
//
//
private SNSMessage readMessageFromJson(String string) {
ObjectMapper mapper = new ObjectMapper();
SNSMessage message = null;
try {
message = mapper.readValue(string, SNSMessage.class);
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return message;
}
}
非常感谢任何建议..
谢谢大家!