C/S B/S架构
C/S架构(Client/Server 客户端/服务器)
B/S架构(Browser/Server浏览器/服务器)
什么是Web
web是sun公司提供的用于开发动态Web的一门技术
常见的web服务器有:tomcat、jetty、resin
tomcat是apache提供的
bin:目录存放二进制文件
conf:目录存放配置文件
webapps:存放web项目
lib:存放依赖第三方包
logs:存放日志文件
temp:存放临时文件
work:存放运行时生成的文件
Tomcat
网页页面和web-INF同级,存放在web目录下
web-INF下的web.xml是配置文件
lib目录放在web-INF下
浏览器url:http://localhost:8080/
配置文件:
tomcat的xml选择2.5的需要手动配置
可以设置优先级load-on-startup
浏览器读取到访问路径为url-pattern
—)精确匹配 /url
—)后缀匹配*.xxx
—)通配符匹配/*
在mapping文件中找到servlet-name
通过servlet找到对应的servlet-name
通过servlet-name找到对应的Servlet类(全限定类名)
<servlet>
<servlet-name>up_download</servlet-name>
<servlet-class>Servlet_up</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>up_download</servlet-name>
<url-pattern>/up_load</url-pattern>
</servlet-mapping>
3.0以上的版本使用注解的方式
//Servlet文件
@WebServlet("/login")
public class ServletLogin extends HttpServlet {
//------------------------------------------
//html文件
<form method="post" action="login">
用户名:<input type="text" name="uname"><br>
密码:<input type="password" name="upwd"><br>
<input type="submit" value="登录" ><br>
</form>
http以及抓包工具esclips中的tcp/ip-monitor
超文本传输协议
请求报文包括:请求行、请求头、空行、请求正文
响应报文包括:响应行、响应头、空行、响应正文
请求报文:
--------请求行 http协议 地址 方式
--------请求头 key-value
--------空行
--------请求正文 数据(post)
响应报文:
--------响应行 http协议 状态码
--------响应头 key-value
--------空行
--------响应正文 数据
常见的状态码
--------4开头客户端错误
--------5开头服务器错误
Servlet
需要导入jar包
Servlet是一个接口
需要进行idea部署tamcat和配置Servlet
Servlet接口
----下面有GenericServlet抽象类
-----------GenericServlet抽象类下有HttpServlet抽象类
----通常我们直接继承HttpServlet类
----可以通过implements实现Servlet接口或者继承HttpServlet类
-------------方法:init\destroy\service
------------------------doGet,如果 servlet 支持 HTTP GET 请求
------------------------doPost,用于 HTTP POST 请求
------------------------doPut,用于 HTTP PUT 请求
------------------------doDelete,用于 HTTP DELETE 请求
Get/Post请求
get请求,地址栏可以看到数据,地址栏或者a标签
传输的数据量小
不安全、效率高
对应doGet方法
post请求,地址栏看不到数据,form表单
可以传输较大的数据
安全,效率相对低
对应doPost方法
<form method="post" action="login">
用户名:<input type="text" name="uname"><br>
密码:<input type="password" name="upwd"><br>
<input type="submit" value="登录" ><br>
</form>
页面里的文本框的名字用于在Servlet中使用req获取请求参数时,使用此名字去获取对应的数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 设置编码得到参数用session传递
*/
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
//获取页面中姓名文本框里的数据
String uname = req.getParameter("uname");
//同理获取页面中密码框的数据
String upwd = req.getParameter("upwd");
//使用session作用域保存数据,request请求在一次请求中有效
//session在一次服务器中有效
HttpSession session = req.getSession();
IManagerService iManagerService= new ManagerServiceImpl();
Manager manager = iManagerService.login(uname, upwd);
if (manager!=null){
session.setAttribute("manager",manager);
req.getRequestDispatcher("showAll").forward(req,resp);
// resp.sendRedirect("showAll");
}else {
resp.getWriter().println("<script>alert('登录失败,请重新登录');window.location='login.jsp'</script>");
// resp.getWriter().println("<script>alert('用户名或密码错误'); window.location='login.jsp' </script>");
// resp.sendRedirect("login.jsp");
}
}
解决乱码的问题:
------7版本以下 get、post请求都会出现乱码
-------------解决请求:
get 请求
将字符串拆解成getbyte 并且设置iso-8859-1
将得到的字节数组转回成字符串 设置编码为utf-8
post 请求
------------ 直接用req.setCharacterEncoding(“utf-8”);
------------解决响应:
---------resp.setContentType(“text/html;charset=utf-8”);
或者
【//设置响应编码格式为utf-8
-----response.setCharacterEncoding(“utf-8”);
-----response.setHeader(“ContentType”,“text/html;charset=UTF-8”);
----】
-------8版本以上,自动解决了get请求的乱码问题,只会出现post乱码
解决:
req.setCharacterEncoding(“utf-8”);
resp.setContentType(“text/html;charset=utf-8”);
请求转发
请求转发:request.getRequestDispatcher(“url路径”).forward(req,resp)跳转到用注解标识的Servlet类
一次请求中有效
通过req.setAttribute(key,value)保存数据
通过request.getAttribute(key);取数据
特点:
有作用域
服务器行为
只做了一次访问请求
浏览器地址不变
信息不会丢失可以进行数据传递
只能在同一个web应用中
重定向
response.sendRedirect(“目标URI”);
没有作用域
可以通过地址栏传数据 ?username=123&pwd=123
属于多次请求
地址栏发生变化
客户端行为
信息会丢失
可以访问外部路径
Servlet生命周期
实例化,只执行一次(设置优先级 可以优先实例化否则和初始化一起,但还是需要先实例化才能使用初始化init方法)
初始化调用init方法
服务service、doGet、doPost
销毁destroy
如果优先级为1,先实例化和初始化,浏览器访问时才调用service方法
如果默认优先级,则浏览器访问的时候才调用实例化初始化和service方法
线程安全问题
线程安全问题
解决方法1、同步代码块,安全但是效率低
方法2、ThreadLocal方式,效率高一点
方法3、作为局部变量放在doPost方法里
方法4、使用SingleThreadModel(不推荐使用)
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private String name;
@Override
public void init() throws ServletException {
System.out.println("UserServlet.init()");
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println(this);
name = Thread.currentThread().getName();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"===>"+name);
}
}
Cookie
http是无连接的,cookie作为标识符帮助服务器识别用户端
cookie存放在本地,4K-8K的内容
具有时间限制(秒)
默认关闭浏览器就失效
服务器发送cookie给浏览器,通过域名和路径保存
cookie只能保存key-value的字符串
创建和使用
response.add 响应加cookie
request.get 请求获得cookie
同域名同路径同名的cookie会覆盖
//创建Cookie
Cookie ck=new Cookie("code", code);
ck.setPath("/webs");//设置Cookie的路径
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0浏览器关闭;<0内存存储,默认-1
response.addCookie(ck);//添加到response对象中,响应时发送给客户端
//注意:有效路径: 当前访问资源的上一级目录,不带主机名
//获取所有的Cookie
Cookie[] cks=request.getCookies();
//遍历Cookie
for(Cookie ck:cks){
//检索出自己的Cookie
if(ck.getName().equals("code"))
{
//记录Cookie的值
code=ck.getValue();
break;
}
}
cookie的编码和解码(7版本以下中文会出现乱码),8以上解决了乱码问题
String name= URLEncoder.encode(“张三”,“UTF-8”);
Cookie cookie=new Cookie(“name”,name);
-----------------------------------------------------------------()
URLDecoder.decode(cc.getName(), “UTF-8”)
// 使用中文的 Cookie. name 与 value 都使用 UTF-8 编码.
Cookie cookie = new Cookie(
URLEncoder.encode("姓名", "UTF-8"),
URLEncoder.encode("张三", "UTF-8"));
// 发送到客户端
response.addCookie(cookie);
if(request.getCookies() != null){
for(Cookie cc : request.getCookies()){
String cookieName = URLDecoder.decode(cc.getName(), "UTF-8");
String cookieValue = URLDecoder.decode(cc.getValue(), "UTF-8");
out.println(cookieName + "=");
out.println(cookieValue + "; <br/>");
}
}
else{
out.println("Cookie 已经写入客户端. 请刷新页面. ");
}
Session作用域
底层是个cookie,是服务器创建的
一次会话中有效,可以发送多次请求,浏览器改变则session改变
默认浏览器关闭就失效
通过req.getSession()获取,然后用session的set、get方法赋值和取值
作用域:浏览器有效,可以任意跳转重定向访问
有不使用时的时间限制
超时session.setMaxInactiveInterval(seconds);//设置最大有效时间(单位:秒)
手工销毁,则失效session.invalidate();//登录退出、注销
getSessionId是cookie里的JssessionID
@WebServlet("/ServletSession")
public class ServletSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf8");
response.setContentType("text/html;charset=utf8");
String uname = request.getParameter("uname");
String upwd = request.getParameter("upwd");
//session和cookie都是浏览会话就结束
//request是一次请求中有效
//session是一次会话有效 服务器创建的
HttpSession session = request.getSession();
if ("admin".equals(uname)&&"123".equals(upwd)){
//将值放入session域中
session.setAttribute("user",uname);
}else {
response.getWriter().println("登录失败");
}
String id = session.getId();
System.out.println("session的id"+id);
// Object jsessionid = session.getAttribute("JSESSIONID");
// System.out.println(jsessionid);
Cookie cookie=new Cookie("name","admin");
response.addCookie(cookie);
}
外部直接访问localhost:8080/ServletIsLogin 显示未登录
进入页面登录,跳转到ServletSession的Servlet中进行操作,登录成功后将数据保存再session中,再次在ServletIsLogin中验证,如果确实登录成功,再次访问localhost:8080/ServletIsLogin时就会显示欢迎【"+user+"】登录
@WebServlet("/ServletIsLogin")
public class ServletIsLogin extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
//判断是否把登录的信息存入到了session中以及对里面的值进行判断
//直接访问这个网站 会显示没有登录,登录之后再访问 session有数据 能够共享
//一次会话中有效即浏览器不关闭
if (user!=null){
response.getWriter().println("欢迎【"+user+"】登录");
}else {
response.getWriter().println("你还未登录,请先登录");
}
}
ServletConfig (了解)
可以在初始化的时候配置固定参数例如用户名和密码
两种方式
第一种通过注解给配置信息进行配置
@WebServlet(value = "/ServletSession",initParams = {
@WebInitParam(name="uname",value = "admin"),
@WebInitParam(name = "upwd",value = "123")}
)
ServletConfig来获取单个Servlet的配置信息
ServletContext获取全局的配置信息
方法二在配置文件中进行配置,每一个Servlet有对应一个ServletConfig 不用担心重名问题,全局配置用<context-param> 标签 与<servlet>标签并列
<servlet>
<servlet-name>ServletSession</servlet-name>
<servlet-class>ServletSession</servlet-class>
//配置初始化信息 配置用户名和密码在这个servlet-class中
<init-param>
<param-name>name</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>12345</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletSession</servlet-name>
<url-pattern>/ServletSession</url-pattern>
</servlet-mapping>
验证码的实现
导入第三方jar包 valicadeCode.jar
//引入第三方jar包 实现验证码 页面的img直接链接到此Servlet实现
ValidateCode validateCode=new ValidateCode(200,30,4,10);
String code = validateCode.getCode();
System.out.println(code);
//页面中显示验证码图形
validateCode.write(response.getOutputStream());
//将code保存在session域中
HttpSession session = request.getSession();
session.setAttribute("code",code);
ServletContext
作用域范围最大,服务器不关闭就始终有效
request、session、servletcontext都是当前Web项目内使用
request一次请求有效
session一次会话即一次浏览器有效
servletcontext当前服务器开启内有效
request、session、ServletContext都能获取到servletcontext
Filter过滤器
可以使用配置文件或者注解的方式设置一些可以改变的值
用config获取配置的信息
Servlet用<Servlet>配置
Filter用<Filter>配置
Listener用<Listener>配置
注意过滤条件,达到条件就放行chain.doFilter(request, response);
条件可以在请求时放在地址栏传递
容器启动时创建,关闭时销毁
uri传递的是较短的路径
url传递的是http开始的长路径
<listener>
<listener-class></listener-class>
</listener>
<filter>
<filter-name></filter-name>
<filter-class></filter-class>
</filter>
@WebFilter(value = "/*",initParams = @WebInitParam(name = "encode",value = "utf8"))
public class EncodeFilter implements Filter {
private static String encode;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse) resp;
//对编码进行过滤
request.setCharacterEncoding("utf8");
response.setContentType("text/html;charset="+encode);
//放行
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
encode = config.getInitParameter("encode");
System.out.println(encode);
}
}
Listener监听器
可以对request、session、ServletContext进行创建销毁的监听和取值赋值的监听
注意加注解@WebListener
@WebListener
public class SessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session注销了");
ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
ArrayList<String> list = (ArrayList<String>)servletContext.getAttribute("list");
Object dName = httpSessionEvent.getSession().getAttribute("dName");
list.remove(dName);
System.out.println(list);
System.out.println(dName);
servletContext.setAttribute("list",list);
}
}