servlet

servlet

  • 1.两种软件架构方式 c/s和b/s的区别

  • Tomcat服务器软件

  • Servlet

  • Servlet应用

  • 状态管理Cookie,Session

  • Filter过滤器,实现自定义过滤规则


    1.服务器

    1.1 web(world wide web)称为万维网,即网站

    作用:表示internert主机上供外界访问的资源

    1.2 internet上供外界访问的资源分为两类:

    静态资源:web页面中浏览的数据不变(html,css

    动态资源:浏览的数据有程序产生,

    不同时间点,不同设备看到的内容不同(jsp,servlet

    1.3在java中,动态web资源开发技术称为javaweb

    1.4 web服务器(运行及发布web的容器)

    只有将开发的web项目放置到该容器中。才能使网络中

    的所有用户通过浏览器进行访问

​ 1.5 Tomcat服务器

特点:免费开源,支持servlet和jsp规范


2.Servlet(重点)

1.servlet: servlet Applet的简称,是服务器端的程序(代码,功能实现)

作用:

  • 接受客户端请求,完成操作
  • 动态生成网页(页面数据可变)
  • 将包含操作结果的动态网页响应给客户端(浏览器)
2.部署web项目:

热部署:更改内容,想获取最新内容,重启tomcat即可

deployment部署

Artifacts项目部署形式

  1. 在tomcat的webapp下创建与项目同名的文件夹
  2. 将idea里编写好的WEB-INF放到该文件夹下
  3. 在WEB-INF下创建classess文件夹
  4. 将idea里build后out下的项目的.class和路径复制到classes中
  5. 打开bat文件,浏览器输入http://localhost:80/项目名称/实体类名

注意:再次编写新的servlet(或重新编译),

都需要手工将新的.class文件部署到tomcat中较为麻烦

👿 :​如何实现自动部署?

3.HTTP协议

1.超文本?

页面,图片,音频等

2.什么是HTTP?

超文本传输协议:HyperText Transfer Protocol

是互联网上应用最广泛的一种协议

它基于请求和响应模式,无状态,应用层的协议

运用于TCP协议(三次握手,四次挥手)之上

3.HTTP特点:

  • 支持客户端(浏览器)/服务器模式

  • 简单快速:客户端只向服务器发送请求方法和路径,服务器即可响应数据,

    因而通信速度很快,请求方法常用的有GET/POST

    • 灵活:Http允许传输任意类型的数据,传输的数据类型由content-type标识
    • 无连接: 每次TCP连接只处理一个或多个请求,服务器处理完客户的请求后,断开连接
    • 无状态:对于事务处理没有记忆能力(http不知道客户端和服务器端发生了什么)

4.Servlet详解(重点

🖍实现Servlet接口与继承GenericServlet类的实现类均与Http协议无关

⏰ 而继承HttpServlet的实现类与协议有关

1.编写Servlet类需要:

  • 直接或间接的实现Servlet接口

  • 继承该接口的类 通过继承GenericServlet或 HttpServlet即可

  • 其中继承GenericServlet抽象类时,只需重写service方法,其他已在该方法里被重写

  • HttpServlet是继承自GenericServlet的基础上的扩展

    不再由service提供单一的服务

    而是根据不同请求方式的不同拆,调用不同do的方法处理请求,这些do方法与http协议有关

    ⛹doPost方法里调用doGet()方法是使得保证了两种请求方式处理的是同一种结果

Servlet接口中包含5个方法:

init(ServletConfig config);
destroy();
ServletConfig getServletConfig();
String getServletInfo();
service(ServletRequest req,ServletResponse res);

public abstract class GenericServlet implements Servlet,ServletCofig,Serializable{}

public abstract class HttpServlet extends GenericServlet {}

⏰ (abstract)抽象方法

  • 必需被子类重写
  • 不能被单独new

⏰ protected修饰的方法:

  • 同一个类中可访问

  • 同一个包中子类无关类可访问

  • 不同包中的子类可访问

servlet配置方式:

💥注解和xml同时配置不冲突,建议使用注解

servlet2.5之前使用web.xml配置

servlet3.0后支持注解配置

web.xml文件元素

  1. url-patten 通配符匹配并不会影响精确匹配
  2. /*通配符会拦截到除精确匹配的通配符
  3. load-on-startup 启动的优先级
  • 正整数或0:容器在应用启动时加载并初始化servlet

    值越小,servlet优先级越高,值相同,容器自己选择顺序来加载

  • 负数或没有设置:被请求时再加载

5.Servlet应用(重点

5.1 Request对象

服务端与客户端打交道时,客户端发送到服务端的请求数据和请求内容都包含在request对象里

⏰ 用户通过页面的提交访问到servlet

客户端发送get请求到servelet后,调用doGet方法,

doGet方法通过request对象的getParameter方法

获得请求发过来的数据

Tomcat7之前get中文乱码,

客户端以UTF-8的编码传输到服务器,而服务器的request对象

使用的是ISO8859-1这个字符编码来接收数据

而tomcat8中的get不会乱码,因为服务器对url的编码可以进行自动转换

tomcat 没有解决post中文乱码

此时需要对request请求对象设置统一的编码:

借助ServletRequest接口继承而来的

setCharacterEncoding(“UTF-8”);

6.实验(Servlet+Jdbc)

概要:

  • database.properties
  • utils
  • entity
  • dao数据访问层
  • service业务逻辑层
  • controller和jsp
  1. 创建admin数据库并添加数据

  2. 需要jar包:存放在web-INF下创建的lib目录下

    servlet-api.jar(2.5版本之后)

    commons-dbutils-1.7-jar

    druid-1.1.5 jar

    mysql-connector-java-5.1.25-bin.jar

3.在src下选择Resource Bundle创建以.properties结尾的database文件

在它下面写数据库连接对象配置,以及druid连接池配置

⭕️记住对这个项目做配置fileEnncoding设置为utf8

4.在src下的项目包下创建一个utils包用于存放DbUtils

DbUtils的功能:

  1. 创建连接池
  2. 获取连接
  3. 事务的控制
  4. 释放资源

5.在src下的项目包下创建一个entity包存放实体类

该类用于完成数据库对应表的映射

6.在src下的项目包下创建dao包,再在dao包下创建impl包

dao数据访问对象层

⏰创建一个接口XxxDao,用于规范实现类的方法(增删查改)

在impl包里实现接口中方法(重写)

7.在src下的项目包下创建service包 sevice给用户的业务功能,

再在service下创建impl包

⏰创建一个接口XxxService

在impl包里实现接口中方法(重写)

8.在src下的项目包下创建serlet包用于存放具体功能的servlet类,配置用注解,后期学习把servlet的包分为了controller控制业务逻辑和jsp页面显示

9.根据业务逻辑 决定在web下是否创建html文件

7-1.转发(服务器端行为)

  • 转发时地址栏没发生变化

  • 重定向时地址栏发生了变化

    即重定向客户端做了两次请求

1.现有问题:

在之前案例中,调用业务逻辑和显示结果页面都在同一个servlet里,应该将业务逻辑和显示结果分离

XxxServlet extends HttpServlet{
    //调用业务逻辑
    //显示结果页面
}

//将业务逻辑与显示结果分离

XxxController extends HttpServlet{
    //调用业务逻辑
}

XxxJsp extends HttpServlet{
    //显示结果页面
}

2.业务,显示分离后,面临的问题:

1.Controller如何跳转到Jsp

解决:转发

转发的作用在服务器端

将请求发送给服务器上的其他资源,以共同完成一次请求的处理

代码:request.getRequestDispatcher().forward(request,response)

使用forward跳转时,是在服务器内部跳转,

地址栏不发生变化,属于同一次请求

2.如何将业务逻辑得到的数据传递给显示结果的jsp

❎ forward表示一次请求,是在服务器内部跳转,可以共享

同一次request作用域中的数据

request作用域:拥有存储数据的空间,作用范围是一次请求有效(一次请求可以经过多次转发)

存数据时

以键值对形式存储在request作用域中

key为String类型,

value为Object类型

取数据时

通过String类型的key访问Object类型的value

7-2.重定向(客户端行为)

1.sendRedirect跳转时,地址栏改变,代表客户端重新发送的请求,属于两次请求

客户端发送请求1到服务器1,服务器1响应给客户端

客户端发送请求2到服务器2,服务器2响应给客户端

服务器

response.sendRedirect(“目标uri”)

URI统一资源标识符:uniform resource identifier

用来表示服务器中定位一个资源,

资源在web项目中的路径:project/source

resp.sendRedirect(“项目/b?username=tom”)

  • response没有作用域,两次request请求中的数据无法共享
  • 传递数据(字符串类型):通过url的拼接进行数据传递 ?后面为拼接的数据
  • 获取数据:request.getParameter(“username”)

总结:

当两个Servlet需要传递数据时,选择forward转发,

不建议使用sendRedirect进行传递

8.Servlet生命周期

实例化-初始化-服务-销毁

初始化:当用户第一次访问servlet时,由容器调用servlet的构造器创建具体的servlet对象

也可以在容器启动之前l立刻创建实例

注意:可以设置servlet是否在服务器启动时就创建

正数, 启动tomcat时,创建具体的servlet对象

负数或不写,被请求访问时才去创建

9.Servlet特性线程安全问题

servlet在访问后,tomcat容器会调用servlet构造器,执行实例化对象,创建一个servlet对象

而tomcat允许同时多个线程并发访问同一个servlet(临界资源)

如果在方法中对成员变量做修改操作,会导致数据不一致,就会有线程安全问题

如何保证线程安全?

  • 尽可能使用局部变量

  • synchronized:将存在线程安全的代码放在同步代码块中

    原子操作(接受参数,调用业务逻辑,客户端响应)上锁

    缺点==:锁的等待释放需要时间,导致多线程并发访问时服务器的效率低==,同一时间只能有一个线程执行操作

  • 实现SingleThreadModel接口:

    这样,每个线程都会创建servlet实例,这样客户端请求就不会存在共享资源的问题,

    但是servlet响应客户端请求的效率太低,且浪费资源所以被淘汰

10.状态管理

1.概念:将浏览器与web服务器之间多次交互当做一个整体来处理

并且将多次交互涉及的数据(状态)保存下来

2.现有问题:

  • http协议是无状态的不能保存每次提交的信息

3.状态管理分类:

  • 客户端状态管理技术:将状态保存在客户端,代表性是Cookie技术

  • 服务器状态管理技术:将状态保存在服务器端,代表性是session技术(服务器传递sessionID时需要使用cookie的方式)和application

    服务端可以响应给客户端多个cookie

    只要保证cookie的名和路径一致即可修改cookie

10-1.Cookie的使用

客户端通过服务端拿到了一个cookie,

二次请求的时候会携带着cookie做访问

1.服务器响应给浏览器的数据,在浏览器访问web服务器的某个资源时得到的(一来一回,即一次请求,一次响应)

  • 一旦web浏览器保存了某个Cookie,那么它每次访问该web浏览器时,将cookie回传给Web服务器

一个cookie主要有标识该信息的名称(name)和值(value)组成

1.//创建cookie
 Cookie ck=new Cookie(name,vlaue);
//设置cookie的路径(哪些资源可以共享该cookie)
ck.setPath("/webs")
//设置cookie生命周期(>0有效期为秒,=0浏览器关闭,<0内存存储,默认-1)
 ck.setMaxAge(-1)
 //添加到response对象中,响应时发送给客户端
   res.addCookie(ck) 
  --------------------------------------------------------  
 //获取cookie  服务端可以响应给客户端多个cookie 
 Cookie[] cookies = req.getCookies();

//通过循环遍历Cookie
//如果客户端没有cookie,获取cookie的话就会有空指针异常,需要加一条判断语句
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                System.out.println(cookie.getName() + ":" + cookie.getValue());
            }
        }
3.//修改cookie
    如果改变cookie的name和有效路径会新建cookie,有效期会覆盖
    原有的cookie 
    
 //浏览器端报500,服务器端出现异常或错误   
 4.//cookie的编码与解码
     Cookie cookie=new Cookie(
                URLEncoder.encode("姓名","UTF-8"),
                URLEncoder.encode("郝飞宇","UTF-8")
                );


 System.out.println(
     URLDecoder.decode(
     cookie.getName(),"UTF-8") 
                        + ":" +
     URLDecoder.decode( cookie.getValue(),"utf-8") );   
    
    
    
10-2.Session

1.概述:

  • session用于记录用户的状态

  • session指在一段时间内,单个客户端与web服务器的一连串相关的交互(多次的请求与访问)过程

  • 在一个session中,客户可能会多次请求访问同一个资源

    或不同的服务器资源

2.原理:

  • 服务器为每一次会话分配一个Session对象
  • 同一个浏览器发起的多次请求,同属于一次会话(session)
  • 首次使用到session时,服务器会自动创建session,并创建cookie存储sessionid发送回客户端

3.session使用:

session作用域:拥有存储数据的空间,作用范围是一次会话有效

而request作用域:也拥有存储数据的空间,但作用范围是一次请求有效

特点:

  1. 一次会话是使用同一浏览器发送的多次请求,一旦浏览器关闭则结束会话
  2. 可以将数据存入session中,在一次会话的任意位置进行获取
  3. 可传递任意数据(基本数据类型,对象,集合,数组)
//获取session对象
//首次使用session时,第一次浏览器的客户端发送了请求过来,服务器就会自动创建session
HttpSession session=request.getSession();

//session保存数据
session.setAttribute("name","Spring");

//session获取数据
//同一个会话中可以共用一个session
        HttpSession session = req.getSession();
        String name = (String) session.getAttribute("name");
        System.out.println("从session中获得了:"+name);

//session移除数据
  HttpSession session = request.getSession();
        session.removeAttribute("name");
第一次访问没有session,第一次触发了创建,请求头给了一个以cookie形式存储的sessionid
 第二次访问时,由于已经创建了且属于同一次会话,就不再新建
 然后把这个sessionid回传给了客户端,告诉他与上一次的请求属于同一次会话

4.session的生命周期:

开始:

第一次使用到session的请求产生,则创建session

结束:

浏览器关闭,session超时,手工销毁

5.浏览器禁用cookie的解决方案

url重写:(重写url,追加sessionid)

String newURL=response.encodeRedirectURL(String url)
//生成重写的url
    response.sendRedirect(newurl)
1.实验servlet完成登录功能

实验流程:

1.login.html里

<form action="/Ser_war_exploded/login"
   method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
 <input type="submit" value="登录">

</form>
1.由于客户端发送给servlet的请求有两种:get/post
get请求:
将提交的数据放在url之后,
以?连接url和传输的数据,参数之间以&相连,
它以明文传递,数据量小,不安全

post请求:
把提交的数据放在Http包的Body中,
密文传递数据,数据量大,安全

所以提交数据的方法选择post


2.值为login的servlet里:

//1.收参之前对字符集做设置,
此处由于请求为post请求
而tomcat没有解决post乱码的方法,
需要借助ServletRequest接口继承而来的
setCharacterEncoding()方法来处理编码方式


/*客户端与服务器发送请求时,请求数据和请求内容都包含在request对象里
所以对象为req
*/
    //注意:如果没有请求,就不需要对请求编码
req.setCharacterEncoding("utf-8");

//同时设置服务端的编码格式
//和客户端响应的文件类型及响应时的编码格式
//此处客户端响应的文件类型为html
response.setContentType("text/html;charset=uft-8)


//1.收参
客户端发送get请求到servelet后,调用doGet方法,

doGet方法通过request对象的getParameter方法

获得请求发过来的数据(请求携带过来的数据)
//getParameter()的返回值为String类型
String username=req.getParameter("username") ;    
 String password=req.getParameter("password");                       
//2.调用业务逻辑
将用户输入的username和password传给login方法
AdminService adminservice=new AdminServiceImpl()
Admin admin=adminService.login(username,password)
                     
                     
//3.处理结果
用户存在,或用户名或密码错误
存在,则响应给客户端一个页面,显示成功
"怎样响应给客户端一个页面?"  
通过response的getWriter方法获得一个流
PrintWriter printWriter=resp.getWriter();

if(admin!=null){
 printWriter.println("<html>");
 printWriter.println("<head>");
 printWriter.println("<meta charset='utf-8'>");
 printWriter.println("</head>")
 printWriter.println("<body>");
 printWriter.println("<h1>登录成功!</h1>");
 printWriter.println("</body>");
 printWriter.println("</html>");    
 
}else{
 ....
}                        
                     
                     
2.展示所有用户功能:

实验流程:

1.AdminDapImpl里:

//创建Apache的queryRunner
private QueryRunner queryRunner=new QueryRunner()

//想要实现事务控制,就要在queryRunner执行方法的时候再去传连接
public List<Admin> selectAll(){
 String sql="select * from admin";
 try{
  BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
List<admin> admins =queryRunner.query(DbUtils.getConnection,sql,
new BeanListHandler<Admin>(Admin.class)) 
    return admins;
 }catch(SQLException e){
     e.printStackTrace();
 }
return null;
}    

2.AdminServiceImpl完成业务层逻辑:

//1.创建AdminDao接口的实现类对象,方便后期调用selectall方法
private AdminDao admindao=new AdminDaoImpl();

public List<Admin> showAllAdmin(){
    //空指针异常的原因:1、没有对new出来的对象进行实例化,或者去数据库里查询一个空的对象;2、对象为null的情况下去调用该对象所拥有的方法或者成员变量造成的。
    List<admin> admin=null;//防止空指针异常
    try{
    //事务前要开启事务
    //因为事务出现错误时无法继续执行下去,使用try..catch能够保证程序继续执行下去
    DbUtils.begin()//自己定义的工具类
        
   List<Admin> admins=admindao.selectAll();
    
    //查到相关内容提交事务
    DbUtils.commit()
    }catch(Exception e){
        DbUtils.rollback();
        e.printStackTrace();
    }
    return admins;
}


3.showAllAdminServlet


resp.setContentType("text/html;charset=utf-8")
//调用业务逻辑
    AdminServerice ads=new AdminserviceImpl();
	List<Admin> adminlist=ads.showAll();//showall方法里调用了dao里的selectall
"怎样响应给客户端一个页面?"  
通过response的getWriter方法获得一个流
PrintWriter pt=resp.getWriter();

//如果结果不为空
if(adminlist!=null){
    pt.println()
    .....
        pt.println("<table>")
        pt.println("<tr>")
        pt.println("<td>username</td>")
        ....
        for(Admin admin:adminlist
           ){
            pt.println("<tr>")
                pt.println("<td>"+admin.getusernmae()+"</td>")
                ....
        }
    	pt.println("</html>")
}else{
    pt.println("<html>")
        ..
        pt.println("<meta> charset=utf-8")
        ..
        pt.println("<h1>用户数据为空</h1>")
    ...
}   
    
    
}

4.showAllAdmin分解1:showAllAdminController

功能:只负责调用业务逻辑功能

//调用业务逻辑:
AdminService adminservice=new AdminserviceImpl();
list<Admin> adminlist=adminservice.showall();


//request存储数据:

request.getAttribute("admins",adminlist);

request作用域:拥有存储数据的空间,
作用范围是一次请求有效(一次请求可以经过多次转发)
1. 若将数据存入request作用域中,可以在一次请求的任何位置获取   
2.可传递任何数据(基本数据类型,对象,数组,集合等)    
3.存数据:以键值对形式存储在request作用域中
    key为String类型,value为Object类型
    request.setAttribute(key,value)
4.取数据:通过string类型的key,访问Object类型的value   

 //通过转发,跳转到显示结果的servlet
 "表面访问的是controller但实际上访问的是jsp" 
   "客户端发送请求到c,c又转发给j,j响应给客户端" req.getRequestDispacher("/jsp").forward(req.resp)
    //通过forward将请求和响应都转发过去
    转发的作用在服务器端,将请求发送给服务器上的其他资源,以共同完成一次请求
    forward表示一次请求,它跳转时,是在服务器内部跳转,地址栏不发生变化属于同一次请求,所以可以共享同一次request作用域中的数据
    

5.showAllAdmin分解2:showAllAdminJsp

//同时设置服务端的编码格式
//和客户端响应的文件类型及响应时的编码格式
resp.setContentType("text/html;charset=utf-8")

//接受request作用域中的数据:
 //注意:接受结果的时候需要类型转换   
    List<Admin> adminlist=
(Admin)req.getAttribute("admins")  
    
  //  "怎样响应给客户端一个页面?"  
通过response的getWriter方法获得一个流
PrintWriter pt= res.getWriter()
  .....  
    
3.实验 session实战权限验证:

session在本次实验中的作用:

  • 权限验证
  • 在一次会话的任意位置获取session里的管理员信息

实验流程:

4.Session实战保存验证码
因为在登录页面的验证码显示时发送了一次请求,得到了一次响应
当我们登录的时候,我们发送了一次新的请求用来收参和做验证码的匹配
所以将验证码保存在session里(多次请求)

实验流程:

1.创建验证码:

  • 导入ValidateCode.jar

  • 在controller下创建生成验证码的servlet

    为什么要用servlet生成呢?

    客户端在访问login.html时来获得验证码

11.ServletContext对象(重点

1.ServletContext(共享的存储区域)概述:

ServletContext对象是全局对象,也拥有作用域,

对应一个tomcat中的Web应用

2.获取ServletContext对象:

我们现在写的servlet都是继承了httpServlet

httpServlet又继承了GenericServlet

  • GenericServlet提供了getServletContext()方法,

    通过this.getServletContext()获取

  • HttpServletRequest提供了getServletContext()

    通过request对象获取

  • HttpSession提供了getServletContext()方法

    通过session对象获取

绝对路径,从根目录为起点到某一个目录的路径;
相对路径,从一个目录为起点到另外一个的目录的路径。

3.ServletContext的作用:

  • servletcontext的getRealPath()

    获取当前项目在服务器发布的真实路径

  • servletContext的getContextPath()

    或request的getContextPath()

    获取当前项目上下文路径(应用程序名称)

  • 全局容器:

    servletContext拥有作用域,可以存储数据到全局容器中

    1.存储数据:sc.setAttribute(“name”,value);

    2.获取数据:

    3.移除数据

  • setvlet特点:

    唯一性:一个应用对应一个servletcontext

    生命周期;

    web服务器启动时创建,服务器关闭时销毁

  • servlet应用场景:

    统计当前项目访问次数

12.作用域总结:

HttpServletRequest:一次请求,请求响应之前有效

HttpSession:一次会话开始,浏览器不关闭或不超时之前有效

ServletContext:服务器启动开始,服务器停止之前有效

13.过滤器:

1.概念:

客户端与服务器目标资源之间的一道过滤技术

2.过滤器作用:

执行地位在servlet之前,

客户端发送请求时,会先经过filter,再到达目标Servlet中

响应时,反向执行filter

3.编写过滤器:

  • 编写java类实现filter接口
  • 在doFilter方法中编写拦截逻辑
  • 在webservlet注解里设置拦截资源路径

4.过滤器配置:

  • 注解配置

  • xml配置:

    ⏰:在filter-mapping标签下的url-pattern里

    设置的是拦截的资源路径,而不是访问的资源路径

5.拦截路径:

  • 精准拦截匹配
  • 后缀拦截匹配
  • 通配符拦截匹配:/* 表示拦截所有

6.过滤器优先级:

在一个web应用中,编写的多个Filter组合起来称为一个Filter链,

它的优先级为:

  • 如果全为注解的话,按照类全名称的字符串顺序决定作用顺序
  • 如果是web.xml按照filter-mapping注册顺序。从上到下
  • web.xml配置高于注解方式
  • 如果注解和web.xml同时配置,会创建多个过滤器对象,造成过滤多次
13-1:过滤器典型应用之权限验证:

HttpServletRequest和ServletRequest都是接口 HttpServletRequest继承自ServletRequest

14.综合案例(EMS)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值