目录
web开发概述
web程序:所有的程序都部署在服务器端,通过浏览器远程访问
服务器:提供服务 1、接收请求 2、响应
广义:软件+硬件
狭义:程序 ——放置文件(项目),供英特网中的其它电脑访问
流程:客户端浏览器访问程序,先通过IP找到服务器地址,端口号找到程序(服务器)
web开发环境搭建
tomcat:apache公司提供的一款开源服务器
- 下载,解压 http://tomcat.apache.org
- 配置JAVA_HOME环境变量
- 在tomcat的bin目录 双击运行 startup.bat命令 启动tomcat
- 访问:IP+端口号
- bin 放着各种命令 startup.bat命令 shutdown.bat
- conf 放着配置文件 列如server.xml 修改端口号
- lib tomcat运行所需要的jar包
- logs 运行产生的日志文件
- temp 临时缓存文件
- webapps 部署web程序的目录
- work 工作目录
创建发布web程序
-
右键项目——>add framework support(变为web项目)
- src:Java代码
- web:配置文件,网页代码
-
自动部署
- add configuration——>加号——>Tomcat Server Local
- Deployment部署——>artifacts:Application context:访问web的根目录
- Update classes and resources:自动更新
Servlet
- 是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
- Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet作用
- 接收客户端浏览器发送的请求
- 调用其他java代码处理请求
- 向客户端浏览器做出响应
Servlet使用
-
导入jar包 servlet-api.jar
-
继承HttpServlet
-
重写父类方法
import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /* 继承 HttpServlet 重写父类方法 配置servlet */ public class DemoServlet extends HttpServlet { /* 构造方法 初始化对象 只被执行了一次,只创建了一个对象, 此对象由服务器创建的, 默认是在客户端第一次访问该servlet时创建 servlet对象 当 <load-on-startup>0</load-on-startup> 值>=0 时,会在服务器启动时创建 */ public DemoServlet() { System.out.println("DemoServlet"); } /* 初始化,当servlet对象创建后,服务器会自动调用init(), 完成一些初始化操作. 如果我们没有需要初始化的操作,也可以不重写init(),但是服务器依然会调用,会调用父类的init() */ @Override public void init(ServletConfig config) throws ServletException { System.out.println("init"); System.out.println(config.getInitParameter("name"));//获得配置文件中的信息 System.out.println(config.getServletName()); } /* 为请求提供服务,每一次http请求,都会调用service(请求,响应) */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("service"); } /* 当servlet对象销毁时,服务器会调用destroy(), 让我完成一些最终的操作(例如保存日志....) 如果我们没有一些最终的操作,也可以不重写destroy(),但是服务器依然会调用父类中destroy() */ /*@Override public void destroy() { System.out.println("destroy"); }*/ }
-
配置Servlet
<!-- _ml:属于标记语言
html:标记内容指导内容如何显示
xml:可扩展标记语言,用来保存数据,保存配置文件数据
web.xml:web程序配置文件,保存各种配置信息,在服务器启动时,由服务器读取-->
<!--配置servlet 把servlet配置进来,服务器就知道有这个类-->
<!--配置reg-->
<!--让服务器知道有这个类-->
<servlet>
<servlet-name>reg</servlet-name>
<servlet-class>com.ff.firstWeb.servlet.RegServlet</servlet-class></servlet>
<!--为Servlet配置一个供前端访问的地址-->
<servlet-mapping>
<servlet-name>reg</servlet-name>
<url-pattern>/reg</url-pattern>
</servlet-mapping>
Servlet生命周期
Http请求
请求行:请求方式:get / post 请求地址URL: Http协议版本:
请求头:包含主机地址,以及客户端的一些环境信息,以键值对的形式传递.
Host: 127.0.0.1:8088 请求的主机地址
请求体:请求体代表着浏览器在post请求方式中传递给服务器的参数,请求体中参数以键值形式传递, 多个用&链接,服务器接收到后再解析.
username=admin&userpwd=123
get&post
get
- 超链接访问,默认是GET方式
- form提交,不指定method,默认为GET方式
post
form提交,指定method=“POST”
区别
- Get方式主要是从服务器获取信息;post主要是想服务器提交信息
- Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在请求体中提交。
- GET方式提交的数据大小受限制一般1kb(不同浏览器也会有不同);而POST则没有此限制。
应用
- getParameter(name) — String 通过name获得值
- getParameterValues — String[ ] 通过name获得多值
- setCharacterEncoding(编码格式)
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
public class Demo1Servlet extends HttpServlet {
//构造方法默认有
//init 不需要刻意不重写,服务器调用父类的
//service 每次请求都要调用,由于http请求分为get,post请求,在servet中两者处理上略微不同,
//所以父类中定义了doGet() doPost()分别处理get,post请求.
//在父类的service方法中写了一个判断 get-->doget post-->dopost
/*
doget()处理get请求
org.apache.catalina.connector.RequestFacade 实现 HttpServletRequest接口
HttpServletRequest :封装了请求的信息,可以从中获取任何请求信息。
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet"+req);
//请求行数据
System.out.println(req.getMethod()); //GET
System.out.println(req.getProtocol()); //HTTP/1.1
System.out.println(req.getServerName()); //localhost
System.out.println(req.getServerPort()); //8080
//请求头
System.out.println(req.getRemoteAddr());//获得客户端的ip
System.out.println(req.getRemotePort());//客户端端口
System.out.println(req.getHeader("User-Agent"));
//接收用户请求的数据 tomcat8.0以后get请求数据的解码方式支持中文
String name = req.getParameter("name");
System.out.println(name);//张三
System.out.println(req.getParameter("age"));
}
/*
dopost()处理post请求
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
req.setCharacterEncoding("utf-8");//设置post请求数据解码格式
System.out.println(req.getParameter("account"));
System.out.println(req.getParameter("passoword"));
System.out.println(req.getParameter("sex"));
String[] courses = req.getParameterValues("course");
System.out.println(Arrays.toString(courses));
//处理 例如调用jdbc处理
//根据处理的结果向客户端做出响应
//Printwriter:单向打印流
PrintWriter out = null;
try {
resp.setContentType("text/html;charset=utf-8");//设置响应内容的编码格式
out = resp.getWriter();
out.println("<h1>登录成功</h1>");
}catch (Exception e){
out.println("<h1>服务器忙,请稍后再试!</h1>");
}
}
//destroy 不需要刻意不重写,服务器调用父类的
}
Http响应
- 通过Response对象设置编码格式
- 通过Response对象获得一个Printwriter打印输出字符流
- 通过流对象打印要输出的内容
//根据处理的结果向客户端做出响应
//Printwriter:单向打印流
PrintWriter out = null;
try {
resp.setContentType("text/html;charset=utf-8");//设置响应内容的编码格式
out = resp.getWriter();
out.println("<h1>登录成功</h1>");
}catch (Exception e){
out.println("<h1>服务器忙,请稍后再试!</h1>");
}
Http状态码
Ajax
Ajax 全称为:“Asynchronous JavaScript and XML”(异步JavaScript 和 XML),
使用 Ajax,我们可以无刷新状态更新页面,对页面中的某个部分进行更新,并且实现异步提交,提升了用户体验。
同步&异步
- 同步提交:当用户发送请求时,当前页面不可以使用,服务器响应页面到客户端,响应完成,用户才可以使用页面。
- 异步提交:当用户发送请求时,当前页面还可以继续使用,当异步请求的数据响应给页面,页面把数据显示出来 。
实现
客户端发送请求,请求交给XMLHttpRequest,XMLHttpRequest把请求提交给服务器,服务器进行业务处理,服务器响应数据交给XMLHttpRequest对象,XMLHttpRequest对象接收数据,由javascript把数据写到页面上
XMLHttpRequest
前端js对象,用来接收servlet响应来的状态码
open(method,URL,async) 建立与服务器的连接
method参数指定请求的HTTP方法,典型的值是GET或POST
URL参数指定请求的地址
async参数指定是否使用异步请求,其值为true或false
//servlet:
// 接收前端发来的数据进行操作,再向前端js返回状态码,前端接收状态码用js对网页进行操作
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class LoginServlet_back extends HttpServlet {
/*
登录处理
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = null;
try {
//响应行(状态码200 404 500) 响应头(setContentType编码格式)
//out.println("登录成功");服务器向客户端输出的内容
resp.setContentType("text/html;charset=utf-8");//响应头
req.setCharacterEncoding("utf-8");//设置解码格式
String account = req.getParameter("account");
String password = req.getParameter("password");
LoginDao loginDao = new LoginDao();
boolean b = loginDao.checkLogin(account, password);
out = resp.getWriter();
//后端只向前端响应一个状态码
if(b){
out.println(0);
//解决方案是使用ajax 从前端向后端进行发起请求交互
//如果是ajax方式提交的数据,那么服务器端响应的数据返回后会交个XMLHttpRequest对象
}else{
out.println(1);
}
}catch (Exception e){
e.printStackTrace();
out.println(2);
}
}
}
//javascript
<script type="text/javascript">
function subform(){
var account = document.getElementById("accountId").value;
var password = document.getElementById("passwordId").value;
//使用XMLHttpRequest对象,发起异步请求
var httpObj = new XMLHttpRequest();
httpObj.open("post","login",true);
httpObj.setRequestHeader("Content-Type","application/x-www-form-urlencoded");//设置提交数据的格式的请求头
httpObj.send("account="+account+"&password="+password);
//接收服务器端响应回来的数据,当发送请求之后,会触发onreadystatechange事件,
//在此事件的回调函数中,获取响应的内容
httpObj.onreadystatechange = function (){
//当对象就绪状态为4,http响应状态码为200时获取响应内容
if(httpObj.readyState==4&&httpObj.status==200){
if(httpobj.responseText==0){
alert("登录成功");
}else if(httpobj.responseText==1{
alert("账号密码错误");
}else{
alert("服务器忙");
}
}
}
}
</script>
JSON
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式
把java中的对象转换成js对象
优点:
- JSON 只允许使用UTF-8编码,不存在编码问题;
- JSON 只允许使用双引号作为key,特殊字符使用
\
转义,格式简单; - 浏览器内置JSON支持。如果把数据用JSON发生给浏览器,可以用JavaScript直接处理
json&jQuery封装
完整流程
Servlet接收客户端浏览器发来的数据,与数据库进行交互,用Gson对象的toJson()方法把对象转换成字符串并返回至前端js,前端js接收到字符串并用 . p a r s e J S O N ( r e s ) 把 字 符 串 转 换 成 j s 对 象 , 将 用 户 信 息 存 储 到 浏 览 器 s e s s i o n S t o r a g e 的 会 话 存 储 中 , 登 录 界 面 用 w i n d o w . s e s s i o n S t o r a g e . g e t I t e m ( " u s e r " ) 拿 到 浏 览 器 会 话 存 储 的 信 息 的 字 符 串 再 用 .parseJSON(res)把字符串转换成js 对象,将用户信息存储到浏览器sessionStorage的会话存储中,登录界面用window.sessionStorage.getItem("user")拿到浏览器会话存储的信息的字符串再用 .parseJSON(res)把字符串转换成js对象,将用户信息存储到浏览器sessionStorage的会话存储中,登录界面用window.sessionStorage.getItem("user")拿到浏览器会话存储的信息的字符串再用.parseJSON(str)转换成对象后显示
import com.ffyc.webpro.dao.LoginDao;
import com.ffyc.webpro.model.User;
import com.google.gson.Gson;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class LoginServlet extends HttpServlet {
/*
登录处理
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = null;
try {
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");//设置解码格式
String account = req.getParameter("account");
String password = req.getParameter("password");
LoginDao loginDao = new LoginDao();
User user = loginDao.checkLogin(account, password);
out = resp.getWriter();
//问题: 从服务器端向客户端要响应更多的数据. 现在响应 int 字符串
//java程序一般将数据封装在对象中,响应到客户端,而客户端是javaScript语言,两边对象格式不一致
//解决: 前面响应字符串,前端可以接收到. 那么在java中需要对 对象中的数据进行转换
// 早期解决方案是将对象中的数据写入到xml文件中,将xml文件返回,这种语言比较麻烦
// 现在诞生了一种轻量级的解决方案: json(javaScript对象表现形式) 是一种轻量级的数据格式,本质是字符串
// 对象{键:值,键:值...} 集合:[{键:值,键:值...},{键:值,键:值...},{键:值,键:值...}.....]
if (user != null) {
Gson gson = new Gson();
String s = gson.toJson(user);
System.out.println(s);
out.println(s);
} else {
out.println(1);
}
} catch (Exception e) {
e.printStackTrace();
out.println(2);
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
function subform() {
//jquery封装的ajax请求, post表示post请求
//$.post("login",{acccount:$("accountId").val(),password:$("#passwordId").val()});
//$("#formId").serialize() 将表单数据序列化 为 键=值&键=值&键=值....
//function(){ } 读取到响应内容后执行 type:json 直接将返回的json格式转为js对象
// res 是一个json格式的字符串
$.post("login", $("#formId").serialize(), function (res) {
var obj = $.parseJSON(res);//json字符串转为js对象
if (obj.id != null) {
alert("登录成功");
//将用户信息存储到浏览器sessionStorage的会话存储中
window.sessionStorage.setItem("user", res);
location.replace("success.html");
} else if (res == 1) {
alert("账号或密码错误");
} else {
alert("服务器忙");
}
});
}
</script>
</head>
<body>
<!--
表单验证
-->
<form id="formId">
账号<input type="text" name="account"> <br/>
密码<input type="password" name="password"> <br/>
<input type="button" value="登录" onclick="subform()">
</form>
<a href="register.html">注册</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-1.8.3.min.js" type="text/javascript"></script >
<script type="text/javascript">
$(function (){
var str = window.sessionStorage.getItem("user");//拿到的是json字符串
var user = $.parseJSON(str);
$("#accountId").html(user.id+":::"+user.account);
})
</script>
</head>
<body>
登录成功<span id="accountId"></span>
</body>
</html>
session
后端为了知道是哪一账号操作,就需要使用session获取用户的信息
session会话:客户端浏览器与服务器交互的整个过程
session对象:在第一次向servlet发送请求时,在服务器端由服务器创建一个session对象,完成会话期间的管理
session实现会话机制
- 浏览器第一次请求(服务器没有id号),创建HttpSession对象,并将对象分配一个会话id号,并将id号响应给浏览器,浏览器就将id号存起来,之后每次向Servlet发送请求时,浏览器会在请求头中将id号向服务器端发送
- 浏览器第二次请求到服务器,服务器就会根据收到的id号查找对象的session对象使用
//获取服务器生成的session对象
HttpSession session = req.getSession();
//向session对象设置一组键值,登录成功后将用户信息存储到一个对象的session对象中.
session.setAttribute("user", user);
获取session:
HttpSession session = req.getSession();
session.getId(); //获取session的id
User user = (User)session.getAttribute("user");//通过前边setAttribute的键获取会话中user对象
//销毁浏览器
session.invalidate();
session生命周期
创建 :第一次访问servlet时,在服务器端创建
销毁:1、服务器关闭 2、会话对象长时间未使用 3、session.invalidate()
设置session会话时间
绝对时间(不管有没有会话):在web,xml中设置
<session-config>
<session-timeout>50</session-timeout> //50分钟自动销毁
</session-config>
未使用销毁时间:session.setMaxInactiveInterval(60) //不使用60秒销毁
安全退出
用户退出时,销毁session
/**
* 安全退出,销毁服务器端的session
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
//销毁浏览器
session.invalidate();
}
function exit(){
if(confirm("您确定要退出吗?")){
//删除前端浏览器存储的用户信息
window.sessionStorage.removeItem("user");
//向服务器发送请求,销毁session
$.get("index",function(res){
location.replace("index.html")
});
}
拦截未登录用户访问
$(function (){
//拿到json字符串
var str = window.sessionStorage.getItem("user");
//前端判断用户是否登录
if(str==null){
location.replace("login.html")
return;
}
var user = $.parseJSON(str);
$("#accountId").html(user.id+":::"+user.account);
})
ServletContext
为了实现web程序中所有的Servlet数据交互,WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的
ServletContext对象,存储一些全局信息
生命周期:开始于服务器的启动,结束于服务器关闭
//servletContext对象全局共享
ServletContext servletContext = req.getServletContext();
getInitParameter(“name”)获得当前应用的初始化参数
setAttribute(“attrname”,value) 设置ServletContext属性并赋值
getAttribute(“attrname”) 获得ServletContext属性指定值
removeAttribute(“attrname”) 删除ServletContext指定属性
过滤器
过滤器位于客户端和web应用程序之间,用于检查和修改两者之间流过的请求
编码过滤器
import javax.servlet.*;
import java.io.IOException;
/**
* 编码过滤器
* @author Deevan
*/
public class EncodeFilter implements Filter {
String code;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init");
code = filterConfig.getInitParameter("encode");
}
//执行过滤代码
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding(code);
//让请求继续向下执行,下一个目标可能是Servlet,也可能是下一个过滤器
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
<!--编码过滤器配置-->
<filter>
<filter-name>encode</filter-name>
<filter-class>com.ffyc.webpro.filter.EncodeFilter</filter-class>
<!--把参数配置到配置文件中,用init中filterConfig.getInitParameter("encode")调用-->
<init-param>
<param-name>encode</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
<!--哪一个请求能够进入这个过滤器-->
<url-pattern>/back/*</url-pattern><!--路径中以back开头的才会进入过滤器,防止html请求-->
</filter-mapping>
sessionID过滤器
import com.ffyc.webpro.model.User;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author Deevan
*/
public class IsLoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//把ServletRequest向下转型为HttpServletRequest对象
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
User user = (User)session.getAttribute("user");
if (user==null){
PrintWriter out = servletResponse.getWriter();
out.println(201);
}else{
filterChain.doFilter(servletRequest,servletResponse);
}
}
}
<!--sessionID过滤器配置-->
<filter>
<filter-name>islogin</filter-name>
<filter-class>com.ffyc.webpro.filter.IsLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>islogin</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
//长时间未操作提示重新登录
function save(){
$.get("back/student",function (res){
if(res==201){
alert("登录失效,请重新登录");
location.replace("login.html");
}
})
}