今天意外发现很久之前写过的一篇网站开发学习笔记,感觉还不错,拿出来记录一下。
网站开发学习笔记:
与服务器交互的方法:
-
在浏览器里输入URL
原理:由浏览器发起一个HTTP GET请求
-
在网页里提交表单
由浏览器发起一个HTTP GET/POST请求
-
在JavaScript里使用AJAX方法
原理:使用jQuery.ajax()函数,令浏览器发起一个HTTP GET/POST请求
-
用Java代码完成完成HTTP请求
使用java的API,完成HTTP请求(可使用apache http-component)
AJAX方法
Asynchronous JavaScript And XML
一种异步更新的方法:指的是在不刷新整个网页的情况,与服务器交互数据,对网页的某个部分做局部更新。
(可以实现交互式网页界面)
实现方法:
使用jQuery提供的函数来实现AJAX交互
-
引入jQuery脚本
-
使用jQuert.ajax()函数
jQuery.ajax()
jQuery.ajax(settings)参数说明
参数settings对象是一个Object(可以认为是一个结构体),有以下属性:
- method:”GET”或”post”
- url: 字符串
- success: 回调函数,AJAX交互成功
- error: 回调函数,AJAX交互失败
AJAX:整体不变,局部更新
实例——与定时器相结合
目标效果:
上面实时显示在线人数(jQuery Timer+AJAX)
限免播放视频(HTML5<video>)
DOM元素的属性:
五类功能:
-
class: 给元素添加/删除class
<div class=”selected highlight”>ssss</div>
-
attr:元素的其他属性
-
Prop:目标对象的成员变量
-
Html:元素的innerHTML
-
元素的value(针对表单元素)
上传数据:
例如,用户在文本框里输入ISBN,Keyword,点检索,查询相关图书
怎么把用户输入的值通过AJAX传到后台呢?
jQuery.ajax({
method: "GET",
url:"servlet/HelloServlet1",
//要上传的数据
data:{
"isbn":isbn,
"keyword":keyword,
},
success:function(data,textStatus,jqXHR)
{
$("#result").html(data);
},
error:function(jqXHR,textStatus,errorThrown){
$("$result").html("error:"+errorThrown);
}
});
AJAX-JSON数据格式
应用场景:
在页面输入一个ISBN点,点“检索” 后台检所得到一本书的详细信息:
Title author isbn publisher
数据格式:
服务器以何种格式返回数据,是核心问题
例如,服务器可以按如下格式返回
Title=xxxx&author=yyyy&isbn=zzzz&publisher=zzzz
这对服务器并不困难,直接用java代码就可以拼凑出来。但是,对于客户端来说,解析这段文本却很困难。
JSON数据格式:
JSON:JavaScript Object Notation
一种文本化表示的JavaScript Object
其格式为:
{
“title”:”xxx”,
“author”:”yyy”,
“isbn”:”zzz”,
“publisher”:”www”
}
其实就是定义一个Object的JavaScript代码样式
JSON数据格式
replyText=
“{“
+””title”:”+”””+title+”””+”,”
+””author”:”+”””+author+”””+”,”
+””isbn”:”+”””+isbn+”””+”,”
+””publisher”:”+”””+publisher+”””
+”}”;
(注:以后将使用API来完成)
以JSON格式返回数据时,前端的解析将十分便捷
JSON格式:就是用JavaScript定义对象的代码格式
JSON API:
显然,手工拼写一个JSON字符串比较麻烦,容易出错,需要一个API来完成
JSON官网:http://www.json.org/
下载JAVA版本的解析器
下载得到的是源代码形式
我们可以直接使用源代码,或者自己打包成jar包json-org.jar
注:能操作JSON的API不止一个,还有其他库也支持JSON
注:在Myeclipse界面下粘贴,会自动把jar配置到Build-Path下
使用JSON API
下面,使用org.json.*提供的API来改编上街可得代码
JSONObject jsReply=new JSONObject();
jsReply.put(“title”,title);
jsReply.put(“author”,author);
jsReply.put(“isbn”,isbn);
jsReply.put(“publisher”,publisher);
String replyText=jsReply.toString();
在涉及页面id有重名时,一定要非常注意!因为在写JavaScript时获取id时可能会蒙圈。
JSON构造:
JSON中,除了字符串值需要双引号,其他的Integer,Boolean,Double型都不需要双引号
{
“id”:123,
“male”:true,
“name”:曾鸿发,
“avg”:98.5
}
注意:Object内部也可以是Object
{
”title”:”学习指南”,
“audio”:
{
”sampleRate”:44100,
“channel”:2
}
“vedio”:
{
“height”:720,
“width”:1080
}
}
注意:JSONObject的属性不分前后顺序
JSON可以把一个Map转成JSONObject
Map values=new HashMap();
Values.put(“id”,123);
Values.put(“name”,”shaofa”);
JSONObject result=new JSONObject(values);
VM.C
已经有一个JSON格式的字符串,可以转成JSONObject或JSONArray
注意:
-
在解析的时候有可能抛异常
//如果str格式不规范,会抛出异常
//若相应字段不存在,会抛出异常
//若字段类型不匹配,会抛异常
AJAX——上行数据格式
上行数据的格式
假设现在下行数据已经确定使用JSON格式
那么,上行数据数据是否有其他选择呢?
默认的上行数据格式:
在使用GET/POST时,默认地,jQuery.ajax()会把数据转成
K1=v1&k2=v2&……的格式
JSON格式的上行数据:
可以令jQuery上传一段JSON格式的数据,方法为:
-
设processData属性为false
processData:false,
Data:”自己的字符串”,
-
设data为一段JSON格式的字符串
怎么把一个JavaScript对象转成JSON字符串呢?
使用jquery.json.js.API
<script src=”jquery/jquery.js></script>
<script src=”jquery/jquery.json-2.3.js></script>
然后就可以转换了:
Var jsonText=jQuery.toJSON(jsReq);
服务器端代码:由于客户端上传的代码是JSON格式所以不能再用getParameter()来获取参数了,改成:
InputStream streamIn=request.getInputStream();
String userText=readAsText(streamIn,”UTF-8”);
JSONObject jreq=new JSONObject(userText);
String reqId=jreq.getString(“id”);
String reqName=jreq.getString(“name”);
String reqPhone=jreq.getString(“phone”);
InputStream.read() 返回类型:int
Int read():
从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
所以,可以把数据以JSON格式上传
注:当数据较为复杂时,应使用这种方式
当要上传的数据比较复杂时,先构造一个JavaScript对象,然后以JSON格式上传
AJAX——其他细节
指定格式:dataType
告诉jQuery:服务器发来的是JSON文本,请自动转成一个对象,
dataType:”json”,
Success:function(data,textStatus,jqXHR)
{
//var result=jQuery.parseJSON(data);
//data:已经转成了Object
}
如果不指定dataType,则jQuery会根据Content-Type,自动判断
-
如果是text/plain,data就是String
-
如果是text/json,data就自动地转成了Object
Shorthand Methods:
jQuery.get()
jQuery.post()
jQuery.getJSON()
RESTful-在APP里访问HTTP服务
在app里访问服务器
Servlet所提供的服务,不仅在浏览器里可以访问,也可以在其他任意app里通过HTTP访问。
服务URL:
http://127.0.0.1/myweb/servlet/HelloServlet
在任意App里,都可以通过HTTP来访问这个服务。
APP:>>>HTTP请求>>>Tomcat
APP:<<<HTTP应答<<<Tomcat
Apache HttpComponents
Java的App项目里,可以使用apache.org下的一个库来完成HTTP交互。
Apache HttpComponentsClient:
Apache下提供了很多开源库/框架,称为Apache Project,在下面找到HttpComponents,其提供了Http的支持。
Apache HttpComponents:
它提供了两个模块,
HttpCore:HTTP服务器应用
HttpClient:HTTP客户端应用
在java项目中添加HttpClient库:
注意:
Java中异常Default constructor cannot handle exception type UnsupportedEncodingException thrown by impli:
默认的构造函数不能处理由父类构造函数抛出的异常类型:UnsupportedEncodingException。必须定义一个明确的构造函数。
这时候,你马上要想到的是,你写的代码是不是有异常要处理或者要抛出,你是不是放在一个类中或者方法中忘记处理异常了。
这样你的异常就好解决了。
注意:
-
在服务器端,建议使用Content-Length方式来发送应答(目的是方便客户端的解析)
-
在客户端,HttpEntity表示发送的数据内容,含Content-Type,Content-Length,charset和正文信息
-
EntityUtils不能接收chunked方式的数据
RESTful-RESTful API(基于JSON)
应用示例:
假设有一个网站,提供电影票订单的功能
普通方式:
-
List_movie.jsp:浏览正在上映的电影列表
-
Book.jsp:预定电影票
也就是说,该网站以WEB形式提供服务,用户必须用浏览器登录该网站才能使用相关服务。
RESTful API:representational state transfer (REST)
可以用另外一种形式提供服务,用户以API调用的方式来访问这些服务。
实现方式:HTTP+JSON(或XML)
例如,安卓app一般都是使用这种接口与后台交互
RESTful API示例:
以上述院线定义服务为例,
提供至少两个服务:
-
/api/ListMovie用于查询电影的列表
(电影名称、主演、票价、区域)
-
/api/Book 用于预定电影票
(用户上传客户信息,用于快递送票上门)
请求:GET
应答:
{
error:
Reason:
Data:[...电影信息]
请求:POST
{
Movieid:
Time:
Client:{用户姓名、快递地址、联系电话}
}
应答:
{
Error:
Reason:
Data:{...订单信息...}
}
一个网站可以用RESTful API的形式来提供服务,客户端通过HTTP+JSON来调用这些服务
日志:
为什么需要日志?
服务器一般都是长年累月运行的,需要把重要的时间记录下来(时间、操作者、事件、其他参数)
日志可以用于分析。
比如,某天发生了一个错误,则需要根据日志来判断是什么事情导致了这个错误。
日志级别:
Trace,
Debug,
Info,
Warn,
Error,
Fatal,
其中,fatal最严重,trace最轻微
(设置级别是为了过滤和分类)
日志的过滤:阀值Threshold
在log4j.properties里可以按级别过滤,让低级别的不显示
-
在调试的时候,一般设为DBG,这样所有>=DBG的日志都会被记录。
-
在正式上线被运行的时候,一般设为INFO,一般只有>=INFO级别的日志才会被记录。
记录器Appender
Appender指定输出目标,log4已经内置了几个类,
Org.apache.log4.ConsoleAppender 控制台
Org.apache.log4.FileAppender 文件
Org.apache.log4.DailyRollingFileAppender 每天一个日志文件
Org.apache.log4.RollingFileAppender 文件过大时,产生一个备份文件(可以指定备份的数量)
指定多个Appender:
Log4j.logger.my=DEBUG,C,R
其中,
DEBUG是总的日志级别
C,第一个Appender的名字,是自己起的名字
R,第二个Appender的名字,随便起
文件上传
目标:客户端选择一个文件,点上传,将文件传给服务器上。
普通表单域:<input>数据较小(短的文本)
文件域:<file>文件数据较大,处理起来相对复杂
前端网页:
<form enctype=”multipart/form-data” action=”servlet/HelloServlet”>
选择文件:<input type=”file” name=”upfile”>
说明:<input type=”file” name=descr”>
<input type=”submit” value=”上传”>
</form>
后台处理:使用apache commons fileupload
-
下载库,放到WEB-INFlibs
-
在doPost()中,调用ServletFileUpload
java.io.FileNotFoundException: .xxxx (拒绝访问。) at java.io.FileOutputStream.open(Native Method) at java.io.FileOutputStream.<init>(Unknown Source) at java.io.FileOutputStream.<init>(Unknown Source) at com.yaohong.test.InputStreamTest.fileInputStream(InputStreamTest.java:13) at com.yaohong.test.InputStreamTest.main(InputStreamTest.java:27)
当遇到这种错误时,先要分析原因,遇到这种状况,是因为你访问的是一个文件目录,如果这个目录没有权限或者目录不存在,就会抛出问题。
比如,我在做项目的时候,先新创文件到c盘目录下,结果有问题,改成f盘后就没问题了。所以在此之前应当看一下该目录的访问权限。
对C盘读写访问权限进行修改后,发现还是行不通,具体原因也不知道为什么,以后再来弄懂吧
文件上传进度的显示(HTML5)
在上节课中,点上传之后,由浏览器负责上传文件,直到完成。完成后显示副武器的应答
缺点:
-
要打开一个新界面
-
不能实时显示进度
文件显示进度一直是一个头疼的问题,不能很好地解决。。。除非浏览器给我们提供API,获取文件的显示进度
HTML对文件上传的支持
-
支持获取文件对象的属性(Name,Size...)
-
支持事件回调
Progress:上传进度
Load:上传完成
Error:出错
Abort:取消
实现:
-
服务器端处理不变,使用apache commons fileupload
-
客户端使用XMLHttpRequest
前端:获取文件的属性
当选中文件后,可以获知文件的属性
Var file=document.getElementById(“fileToUpload”).file[0];
$(“#fileName”).html(“Name:”+file.name);
$(“#fileSize”).html(“Size:”+file.size);
创建一个Filter
应用背景:在网站有一个admin目录,下面的网页和资源只允许“admin”账户访问(超级管理员)。
这意味着,如果当前没有用户登录,或者用户名不是“admin”,都不允许访问admin/下的任何资源。
例如,当用户在浏览器里输入
http://127.0.0.1:8080/myweb/admin/aaa.jpg时,应提示其无权访问!
Filter过滤器:
过滤器:当Tomcat收到WEB请求时,首先调用过滤器来处理,过滤器可以拦截请求。
例如,
设置了三个过滤器
[filter 1]
[filter 2]
[filter 3]
一个请求到来时,首先交给filter1过滤,如果filter1没有拦截该请求,则交给下一个filter2过滤。。。
添加一个Filter
-
创建一个类,
Public class AsSampleFilter implements filter
-
在web.xml中配置
<filter>
<filter-name>AsSampleFilter</filter-name>
<filter-class>my.AsSampleFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AsSampleFilter</filter-name>
<url-mapping>/admin/*</url-mapping>
</filter-mapping>
即:当请求的URL为/admin/*格式时,将交给AsSampleFilter处理
Filter拦截请求
在Filter里,可以决定是否拦截请求:
代码框架为:
Void doFilter(request,response,chain)
{
If(需要拦截)
{
...处理该请求..
}
Else
{
chain.doFilter(request,response); //不感兴趣
}
}
应用1:
检查用户是否为“admin”,
如果不是,则跳转到登录页
Response.sendRidirect(...);
应用2:只有某固定网段的IP才允许访问/admin/*
Filter的更多细节:
-
Filter的生命期
Filter在APP启动时一并创建,直到APP被卸载时才被删除
也就是说,在app运行期间,filter的实例是一直存在的。
Init():初始化
Destroy():退出时执行
filter的配置参数:
Filter可以设置一些配置参数:
<filter>
<filter-name>AfSampleFilter<filter-name>
<filter-class>my.AfSampleFilter<filter-class>
` <!-- filter的配置参数 -->
<init-param>
<param-name>id</param-name>
<param-value>201501</param-value>
</init-param>
<init-param>
<param-name>loaction</param-name>
<param-value>aaa</param-value>
</init-param>
</filter>
多项url-pattern:
同一个filter可以设置多个url-pattern
<filter-mapping>
<filter-name>AfSampleFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AfSampleFilter</filter-name>
<url-pattern>*.jsp</url-pattern</url-pattern>
</filter-mapping>
则凡是*.html和*.jsp都会被交给AfSampleFilter过滤
FilterChain多个Filter串连
在web.xml中,可以添加多个Filter,它们组成的一串叫做FilterChain
[filter 1]
[filter 2]
[filter 3]
[filter ...]
web请求时会依次交给它们过滤
注:多个filter会按web.xml的出现的顺序排列
自定义应用框架:
其实,Servlet机制就是一个应用框架。它是Tomcat自带的应用框架。
使用Filter+Reflection技术,可以添加一套自定义的应用框架。(如:比较著名的struts框架)
应用实例:
在服务器添加RESTful API的一般流程为:
-
添加xxxServlet类
-
在web.xml里添加该servlet的配置
-
在doPost()
读取URL里的参数
读取上传上来的HTTP请求正文reqText
---------------处理请求---------------
返回reqText给客户端
可以把这个标准改造成一个应用框架,以提高开发效率
Dom4j是用来解析xml文件的。
添加 setters 框架直接把 URL 中附带的参数通过 setters 设置到成员变量中。例如,请求为: /hello.api?id=201601&name=shaofa 则框架会通过 setId 和 setName 来设置成员变量的值。
使用框架的好处:
-
精简代码
-
把业务处理与框架流程独立开来,写api的人可以不必懂servlet
总结:该框架设计过程中,所应用到的最主要的反射机制在于当输入网页地址时附加的参数能够上传到对应的服务器进行解析,主要是设置了对应的setter,我想主要是因为对解析参数值的过程利用了Class函数
文件的下载和上传:
-
WEB-INF 和 META-INF 下的文件不支持下载
-
Web Application 目录之外的文件不支持下载
前端权限检查:
前端权限检查:借助于浏览器缓存,在前端自行完成检查。
-
在登录返回时,将当前用户的信息存在缓存里。
sessionStorage.setItem("key",value)
-
在点发帖时,从缓存里检查当前用户的信息。
value=sessionStorage.getItem("key")
sessionStorage是浏览器对象,可以用JavaScript来访问它,前端页面可以把数据存储到这里。
注意:
-
当浏览器关闭时,sessionStorage的内容被清空。
-
只能存储字符串,如果想存储一个对象,需要转成字符串。
sessionStorage.setItem("key",JSON.stringify(obj));
var obj=JSON.parse(sessionStorage.getItem("key");
用户以手机号进行注册:
手机短信验证:
用户在以手机号进行用户注册时,需要填写验证码
-
绑定手机号
-
点“发送验证码”...后台系统将发送一个验证码到这个手机号,同时把验证码放到session中。
-
用户在手机上查看短信验证码,填写到页面
-
用户点击“注册”,后台检查验证码是否正确
多重过滤:
FilterChain,过滤器
指一个请求可能被多个过滤器多次过滤
chain.doFilter(request,response)
告诉Tomcat让后面的Filter继续处理这个请求。
Filter Chain里的顺序:
当有多个Filter时,按出现的先后顺序依次执行:
web.xml方式:按出现的顺序排列
注解方式:按类名的顺序排序