项目很小,就是一个企业站的前后台,主要包括新闻模块、产品模块、视频模块、留言。没有什么技术上的难点,大部分就是CRUD操作。开始之前评估开发时间为4天,实际coding时间为3天,debug时间为2天,关于debug时间较长的问题,后面有较为详细的分析。
相比MVC 3,个人感觉并没有太大的变化,也许是一些新特性没有用到。
除开没有后台页面等其他因素,自身原因分析如下:
虽然项目需求简单,但有些地方开始时疏于沟通,最终所省掉的时间还是用在了debug上,甚至更多。
仅在开发阶段使用chrome浏览器,ie系也仅测试ie10,其余未考虑,后续在浏览器兼容性方面的调试花费了较多的时间。
例如如下的问题:
将
this.attr("novalidate", "novalidate");
修改为:if (typeof (Worker) !== "undefined") { this.attr('novalidate', 'novalidate'); }
尝试了很多网上的解决方案,均不管用,后来使用了一个非常规手段,就是给浏览器加上强制使用ie8模式的meta信息
版本匹配问题:经测试:jquery-1.8.2 with jquery.validate-1.9正常
很多api需要现查官方文档,而且官方站点还需FQ。同时在集成uploadify到ckeditor里面的时候,也花费了较多的时间,主要是用在查官方文档上面。这块写了较多的js代码,在后续浏览器兼容性方面调试也比较麻烦。
网上大部分的情况是firefox和chrome同时出现此问题,基本都是说session的原因,但我的环境chrome却没有出问题。我的解决方案比较简单,就是对上传文件的后台action取消授权检查。应该还是跟session有关,更好的解决方案可查询谷歌。
主要是开始无法新建sqlite数据源,ef的设计器总是报错,无法通过数据库更新实体等。另外sqlite中文模糊查询问题。
需要到sqlite官网下载合适的数据源驱动程序http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
原来使用的方式:dbcontext.Post.Where(t=>t.Name.Contains(s)),对应的sql语句为charindex,改为:list = context.Database.SqlQuery(string.Format("select * from product where name like '%{0}%'",arcTitle)).AsQueryable();
最近做WebService,最开始用weblogic自带的集成IDE---Eclipse做,,死活出不来,很惨很惨,然后换了个myeclipse8.6来整,使用Tom猫部署。
基于JAX-WS做,然后使用SOAP消息调用WebService。整了1个多小时,坑。。。
虽然关于HelloWorld的例子满天飞,但是今天还是从该出起,完整的记录点点滴滴。
整体工程:
步骤:
一:首先加入JAX-WS核心包:
Book类为实体类,包含基本的ID,名称之类的。
以其中的UpdateBook作为例子:
二:创建BookService接口:
@WebService @SOAPBinding(style=SOAPBinding.Style.RPC) public interface UpdateBook { public String update(int id1, int id2, String name); }
三:创建BookService接口实现类:
@WebService(endpointInterface = "com.bfchuan.server.UpdateBook") public class UpdateBookImpl implements UpdateBook{ @Override public String update(int id1, int id2, String name) { if(id1==1&id2==2&name.equals("bfc")){ return "SUCC"; }else{ return "Fail"; } } }
WebService为注解,该注解能设置很多选项:
- namewsdl:portType 的名称。缺省值为 Java 类或接口的非限定名称。(字符串)
- targetNamespace指定从 Web Service 生成的 WSDL 和 XML 元素的 XML 名称空间。缺省值为从包含该 Web Service 的包名映射的名称空间。(字符串)
- serviceName指定 Web Service 的服务名称:wsdl:service。缺省值为 Java 类的简单名称 + Service。(字符串)
- endpointInterface指定用于定义服务的抽象 Web Service 约定的服务端点接口的限定名。如果指定了此限定名,那么会使用该服务端点接口来确定抽象 WSDL 约定。(字符串)
- portNamewsdl:portName。缺省值为 WebService.name+Port。(字符串)
- wsdlLocation指定用于定义 Web Service 的 WSDL 文档的 Web 地址。Web 地址可以是相对路径或绝对路径。(字符串)
这些属性如果不设置,在WSDL里面会有默认值。当你每将一个类发布成服务的时候,就会有一个WSDL描述文件。
第四:增加WSDL文件,在该项目中,该文件如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.3-hudson-390-. --> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://server.bfchuan.com/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="UpdateBookImplService" targetNamespace="http://server.bfchuan.com/"> <types/> <message name="update"> <part name="arg0" type="xsd:int"/> <part name="arg1" type="xsd:int"/> <part name="arg2" type="xsd:string"/> </message> <message name="updateResponse"> <part name="return" type="xsd:string"/> </message> <portType name="UpdateBook"> <operation name="update" parameterOrder="arg0 arg1 arg2"> <input message="tns:update"/> <output message="tns:updateResponse"/> </operation> </portType> <binding name="UpdateBookImplPortBinding" type="tns:UpdateBook"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="update"> <soap:operation soapAction=""/> <input> <soap:body namespace="http://server.bfchuan.com/" use="literal"/> </input> <output> <soap:body namespace="http://server.bfchuan.com/" use="literal"/> </output> </operation> </binding> <service name="UpdateBookImplService"> <port binding="tns:UpdateBookImplPortBinding" name="UpdateBookImplPort"> <soap:address location="http://localhost:8080/WebService/UpdateBookImplPort"/> </port> </service> </definitions>
现在为WSDL做一一的解析:
1.Type:
其中Type为空,为什么呢?
因为Type是用来导入和局部定义web服务交换信息要使用的XML Schema中的简单类型定义-------所有的Web服务将能够随时使用它们,因此,在这个项目中没有必要在这此处放入任何东西。通常来说,WSDL将Type定义成指向外部的schema。
举个例子,一个需要使用Type的格式如下所示:
<type> <xsd:Schema> <xsd:import namespace=http://soacookbook.com/ SchemaLocation-"http://localhost:7777/Test/HelloWSService?sxd=1"/> </xsd:Schema> </type>
2.Message
WSDL的Message部分包含请求和响应定义,与服务器通信时,要使用的这些请求和响应,你可能会注意到,请求和响应都是各自对应一条信息。请求信息与方法调用名称相同,因此此处采用的是RPC样式。响应名称是按照在操作后附加“Response”的方式给出的,这是JAX-WS的规范的默认方式。
对于请求:
<message name="update"> <part name="arg0" type="xsd:int"/> <part name="arg1" type="xsd:int"/> <part name="arg2" type="xsd:string"/> </message>
每一个消息,都包含一个part子元素,消息part与方法中的参数类似,具有名称和类型。
第一个part的名称是arg0,后面的以此类推,这个名字也是客户端调用的时候需要传递参数时候使用的名称(针对SOAP消息调用服务,后面会说到)
当然这些名称是系统默认的,你可以对它进行定制。
对于响应:
<message name="updateResponse"> <part name="return" type="xsd:string"/> </message>
由于默认参数的样式纸是:wraped,Web服务返回值将封装在单个元素中,名称为return,你可以通过它提取剩余的载荷。
3.Binding
WSDL的Binding部分指定于服务器之间的消息传递方式。默认是SOAP,其他高级的选项包括HTTP,JSM,SMTP和TCP。由于通过对UpdateBook接口使用了这个注释:
@SOAPBinding(style=SOAPBinding.Style.RPC)
指定希望将服务绑定带SOAP,因此会获得SOAP绑定作为消息传输方式
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
这里指定了一个地址,这意味着服务将使用SOAP1.1作为消息的发送和接受的协议。
还有个属性:style=“rpc”这个,该WSDL编写它是因为这个接口存在以上的那个注解。
4.Service
WSDL的Service部分指定服务名称将是UpdateBookImplService 。该名称是在定义服务器的类名称后面加上Service的,这是JAX-WS在没有自定义名字的时候采用的默认命名。
这儿还指定使用SOAP绑定UpdateBookImplPort端口,端口命名也是默认,规则你懂的。
该部分带有SOAP的前缀,说明他们来自:"http://schemas.xmlsoap.org/wsdl/soap/"命名空间。
此处的Location属性指定可以在什么位置调用该服务,以及将使用哪些客户端来调用。
第五:创建sun-jaxws.xml文件,该文件如下所示:
<?xml version = "1.0"?> <endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"> <endpoint name="UpdateBookImplPort" implementation="com.bfchuan.server.impl.UpdateBookImpl" url-pattern="/UpdateBookImplPort"> </endpoint> </endpoints>
该文件中,定义了该实现类的访问端口UpdateBookImplPort,即当访问该端口的时候,去找com.bfchuan.server.impl.UpdateBookImpl这儿。
第七:配置Web.xml文件
相信这个文件,都不陌生。该文件如下所示:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <description>JAX-WS endpoint - HelloImplService</description> <display-name>HelloImplService</display-name> <servlet-name>HelloImplService</servlet-name>
<!--配置监听---> <servlet-class> com.sun.xml.ws.transport.http.servlet.WSServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>
<!--这儿的UpdateBookImplPort就是对应sun-jaxws.xml中的UpdateBookImplPort,当访问这个UpdateBookImplPort的时候由
这儿转向sun-jaxws.xml的UpdateBookImplPort,再由UpdateBookImplPort去找实现类--> <servlet-mapping> <servlet-name>HelloImplService</servlet-name> <url-pattern>/UpdateBookImplPort</url-pattern> </servlet-mapping>
<welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <listener> <listener-class> com.sun.xml.ws.transport.http.servlet.WSServletContextListener </listener-class> </listener></web-app>
于是整个WebService的文件解析完了。
流程为:
首先web.xml接收到请求port的请求------然后在sun-jaxws.xml中找对应的port-----找到对应的实现类
为什么他能找到?WSDL在这儿起了管理作用,定义了相关信息,将某个port和某个service绑定在一起。
然后就是客户端。客户端我采用SOAP消息调用service的服务。
现在对SOAP的消息做一个介绍:
SOAP基于HTTP协议传输,(通常是这样,当然也可一使用JSM和其他机制)。合并防火墙通常允许交换已有HTTP流量,并使用适当机制来处理流量,包括防火墙规则,分支网络等。
SOAP被创建用来特定满足基于SOAP的WEB服务开发新手的需要,他可以手动操纵SOAP信封。关于SOAP信封的消息,度娘很多了。
下面基于该例子做一个基于SOAP消息调用服务:
一:首先创建一个java工程:
第二:创建一个文件,名字为:book.msg
内容为:
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <ns1:update xmlns:ns1="http://server.bfchuan.com/"> <arg0>3</arg0> <arg1>3</arg1> <arg2>bfc</arg2> </ns1:update> </soap:Body> </soap:HelloImpl>
这儿的arg0分别对于WSDL里的那个参数,还记得吧。
这里的update对应WSDL里的操作数。
其他的为SOAP的消息体。
SOAP的消息载体写好了,现在我们需要发送消息。
第三:编写java类发送SOAP消息:
public class UpdateBook { public static void main(String[] args) { doSoapPost(); } public static void doSoapPost() { try { //First create the connection SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance(); SOAPConnection connection = soapConnFactory.createConnection(); //Next, create the actual message MessageFactory messageFactory = MessageFactory.newInstance(); SOAPMessage message = messageFactory.createMessage(); //Create objects for the message parts SOAPPart soapPart = message.getSOAPPart(); SOAPEnvelope envelope = soapPart.getEnvelope(); SOAPBody body = envelope.getBody(); //Populate the Message StreamSource preppedMsgSrc = new StreamSource( new FileInputStream("msg/updatebook.msg")); soapPart.setContent(preppedMsgSrc); //Save the message message.saveChanges(); //Check the input System.out.println("/nREQUEST:/n"); message.writeTo(System.out); System.out.println(); //Send the message and get a reply //Set the destination String destination = "http://localhost:8080/WebService/UpdateBookImplPort"; //Send the message SOAPMessage reply = connection.call(message, destination); // Check the output System.out.println("/nRESPONSE:/n"); //Create the transformer TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); //Extract the content of the reply Source sourceContent = reply.getSOAPPart().getContent(); //Set the output for the transformation StreamResult result = new StreamResult(System.out); transformer.transform(sourceContent, result); //Close the connection connection.close(); } catch(Exception e) { System.out.println(e.getMessage()); } } }
对于该代码不做过多的说明,当该程序运行后,结果如下所示:
/nREQUEST:/n <?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soap:Body> <ns1:update xmlns:ns1="http://server.bfchuan.com/"> <arg0>2</arg0> <arg1>2</arg1> <arg2>"bfc"</arg2> </ns1:update> </soap:Body> </soap:HelloImpl> /nRESPONSE:/n <?xml version="1.0" encoding="UTF-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body><ns2:updateResponse xmlns:ns2="http://server.bfchuan.com/">
<return>Fail</return>
</ns2:updateResponse>
</S:Body>
</S:Envelope>
前面是发送的SOAP消息
后面是服务器返回的SOAP消息
如果说你返回的的是个对象,比如查询某个Book,那么返回的服务的SOAP是如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:byBookResponse xmlns:ns2="http://server.bfchuan.com/">
<return><desc>BBB</desc>
<id>2</id>
<name>AAA</name>
</return>
</ns2:byBookResponse>
</S:Body>
</S:Envelope>
该SOAP返回的是一个对象。
最后题外话:
对于WebService的架构方式,有JAX-WS还有Xfire。对此做个比较:
1) 用基于jax-ws的Client端调用基于XFire和jax-ws的WebService都没有问题;
而用基于XFire的Client端调用基于XFire的WebService存在问题(什么原因目前还不明);
2) 基于Jax-ws的Client端只能通过解析WSDL文档的方式来调用WebService,不可以使用将WebService的接口抓到本地进行掉用的方式;
基于XFire的Client端则能够通过两种方式来调用WebService:(但目前这两种方式只针对XFire发布的WebService)
(1) 将WebService的Interface抓到本地,进行调用;
(2) 通过得到WebService的WSDLFile或是WSDL的URL,解析WSDL来调用WebService;
3) 基于jax-ws的WebServiceClient端可以建立在任何Project中;
基于XFire的WebServiceClient端则必须建立在WebServiceProject中;
对于非WebServiceProject的Project要想调用基于XFire的WebService必须将其Interface抓到本地进行调用;
4) 基于Jax-ws发布的WebService只发布WSDL文档,
基于XFire的WebService则会发布WSDl+服务接口;
5) 基于Jax-ws发布的WebService会显示的产生WSDL文档;
基于XFire发布的WebService则只是在调用时由服务器产生临时的;
6)Jax-ws设计了监听器机制,在WEB.xml中已经能看到监听类的配置了;XFire没有;