登陆

javaweb2

admin 2022-11-24 5人围观 ,发现0个评论

Servlet核心

1.核心类与接口

  1. init:完成初始化操作

    • 只会执行一次

      • 没有配置1时才只会执行一次

      • 在实例类对象中配置(注解方式)

        @WebServlet(vlue="路径",loadonstartup=1) 
      • 如果有多个service配置了loadonstartup,里面的数字就是在服务器中创建示例的顺序

    • init方法在执行的时候,对象已经被创建出来了

  2. service:处理用户请求的核心方法

    • 用户每发送一次请求,server方法就会执行进行
  3. doGet,doPost:根据客户端的请求方式,如果是get则调用doGet,如果是post则调用doPost.....

  4. destroy:Tomcat服务器在销毁对象之前,会调用一次destroy方法

    • 只会执行一次
    • destroy方法执行的时候,对象的内存还没有被销毁,即将被销毁
    • destroy方法中可以编写销毁前的准备
  5. 编写一个抽象类,有一个抽象方法service

    • 实现servlet接口

    • 以后编写的所有servlet类都继承这个抽象类,重写service方法即可

  6. 执行流程

    • 按照1234下来

2.线程安全问题

  • 因为servlet实例是单例模式,当多个客户端并发访问同一个servlet类时,Tomcat会创建多个线程,多个线程会使用同一个seven实例,有可能会导致线程安全问题,那如何保证线程安全呢?

2.1实现singlethreadmodel接口

  • 这种方式虽然避免了多线程使用通过servlet实例的请求,但是使用这种方式会导致客户端的请求响应效率变低,增加了服务器因频繁创建和销毁servlet实例的开销,因此这种方式不建议使用(已经淘汰)

2.2使用synchronize同步锁

  • 在实例类的do方法中锁住this即可

    do方法{  	synchronize(this){     //其他代码     } } 

2.3建议

  • servlet类中尽量不使用全局变量
    • 因为定义全局变量的话,这个变量是多个线程中共享的,就有可能因为同时修改这个变量导致并发问题
    • 因此我们可以将变量定义在处理业务的do方法中,定义为局部变量之后,每个线程都有属于自己的局部变量

3.servlet开发技术

3.1request对象

  1. 接收请求行数据

    1. 获取请求方式
      • request.getMethod();
    2. 获取请求url
      • request.getRequestURL();
    3. 获取请求url上的参数
      • request.getParameter("值");
    4. 获取请求协议
      • request.getProtocol();
  2. 接收请求头数据

    1. 获取请求头中所有的key
      • request,getHeaderNames();
      • 返回的值是枚举
    2. 获取请求头中对应的key
      • request,getHeader("值");
  3. 接收请求正文数据

    • 获取请求正文

      • request.getInputStream();

      • //使用 //获取正文 ServletInputStream inputStream = req.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); //从输入流中读取数据 String s = reader.readLine(); System.out.println(s); 

3.2乱码问题

  • 产生

    • 客户端提交的数据通过网络发送到服务器,传输的过程数据通常会进行编码,服务器会对数据进行编码,如果服务器使用的解码方式与网页的原始编码不一致,将会导致服务器的解码出现乱码
  • get问题

    • get方式提交的数据会拼接在请求行的URL后面进行传递,不同的浏览器处理方式是不一样的,有的浏览器会进行编码,有的浏览器则会直接提交
    • 数据到达服务器之后,服务器会根据参数的编码方式对参数进行解码,如果没有编码则服务器直接接收,如果进行了服务器能够解析的编码,服务器也会进行转换
  • get解决

    • 在Tomcat的conf/server.xml中配置URL的编码方式

      <Connector post"8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8" /> 
  • post问题

    • post方式提交表单数据是通过请求正文进行传递的,会对数据进行编码;Tomcat会对URL传递的参数进行解码,但是不能对请求正文进行解码,因此需要我们在server类中接收数据之前对客户端提交的请求数据进行编码设置;
  • post解决

    • request.setCharaterEncoding("utf-8");

3.3response对象

  1. 设置响应状态行

    1. 设置状态中的状态码
      • response.setStatus(数字);例200
  2. 设置响应头

    1. 设置响应客户端的数据格式

      • response.setContentType("数据格式");例text/html
    2. 设置响应客户端的数据长度

      • response.setContentLength(数字);例1024
    3. 设置其他的响应头属性

      • response.setHeader("属性",格式);

      • //例 response.setHeader("ContentType","text/html"); //等价于 response.setContentType("text/html"); 
  3. 设置响应正文

    • 设置响应客户端的数据编码格式
      • response.setCharacterEncoding("编码格式");例utf-8

4.Servlet练习

4.1环境准备

  1. 创建一个java web工程

    1. 右击模块->选择Add Framework Support..
    2. javaEE中选择Web Application
    3. 默认为4.0版本和创建一个web.xml文件
    4. 默认生成一个web目录(就是项目的名字)
  2. 搭建jdbc环境

    1. 导入jdbc所需的驱动jar包,数据库连接池jar包,DBUtils.jar包

      1. 在web-inf中新建一个lib目录,全小写

      2. 将jar包放入进来

      3. 添加到模块

        image-20221122211926813

    2. 配置连接池信息

      1. 在项目中新建一个properties文件存放连接池信息

      2. # 数据库连接池信息 url=jdbc:mysql:///db-sgms?characterEncoding=utf8 username=root password=123456 driverClassName=com.mysql.cj.jdbc.Driver # 连接池属性 # 连接池初始化连接数 initiaSize=10 # 最大的连接数 maxActive=50 # 最小空闲数 minIdle=5 # 超时等待时间(毫秒) maxWait=30000 
    3. jdbc连接并且获取对象

      • package utils;  import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import com.mysql.cj.SimpleQuery;  import javax.sql.DataSource; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties;  public class DruidUtils {     private static DruidDataSource druidDataSource;     static {         try {             //导入配置文件,获取连接池对象             InputStream is = DruidUtils.class.getResourceAsStream("Druid.Properties");             Properties properties = new Properties();             properties.load(is);             druidDataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);             DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);         }catch (Exception e){             e.printStackTrace();         }     } //从连接池中获取连接池对象     public static DataSource getDataSource() {         return druidDataSource;     }     public static Connection getConnection(){         Connection connection = null;         try {             connection = druidDataSource.getConnection();         }catch (SQLException e){             e.printStackTrace();         }         return connection;     } } 
    4. 数据库环境准备

      • -- 学生信息表 create table students( 	stu_num char(5) primary key, 	stu_name varchar(20) not null, 	stu_gender char(2) not null, 	stu_age int not null, 	stu_pwd varchar(20) not null );  -- 课程信息表 create table courses( 	course_id char(6) primary key, 	course_name varchar(50) not null );  -- 学生成绩表 create table grades( 	gid int primary key auto_increment, 	snum char(5) not null,   	cid char(6) not null,      score int not null ); 

4.2练习要求

  • 根据项目业务流程图,完成需要数据库操作
    • 学生登录实现:
      • 根据输入的学号和密码查询学生信息,如果查询到了说明学号密码输入正确,登录成功;
      • 根据输入的学号查询学生,如果查询到了说明学号正确,再比较输入的密码和查询出来的密码是否一致,如果一致则登录成功;
    • 查询成绩:
      • 根据学号和课程号从成绩表中查询成绩
  • image-20221123164935222

4.3代码实现

4.3.1创建Student和StudentDAO

  • 根据学号和密码查询学生信息,验证是否登录成功

    package dto; //学生信息类 public class Student {     private String stuNum;     private String stuName;     private String stuGender;     private int stuAge;     private String stuPwd;     //setget无参有参方法 } 
    package dao;  import dto.Student; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import utils.DruidUtils;  import javax.management.Query; import java.sql.SQLException;  public class StudentDAO {     public Student QueryStudentNumAndPwd(String stuNum,String stuPwd) {         //如果查询不到就是为null         Student student = null;         try {             //定义SQL语句             String sql = "select stu_num stuNum,stu_name stuName,stu_gender stuGender,stu_age stuAge,stu_pwd stuPwd from students where stu_num=? and stu_pwd=?";             //查询             QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());             student = queryRunner.query(sql,new BeanHandler<Student>(Student.class),stuNum,stuPwd);         }catch (Exception e){             e.printStackTrace();         }         //返回结果         return student;     } } 

4.3.2创建Grade和GradeDAO

  • 根据学号和课程号查询学生的科目成绩

    package dto;      public class Grade {       private String snum;       private String sname;       private String cid;       private String cname;       private int score;   	//setget无参有参方法   } 
    package dao;      import dto.Grade;   import dto.Student;   import org.apache.commons.dbutils.QueryRunner;   import org.apache.commons.dbutils.handlers.BeanHandler;   import utils.DruidUtils;      import java.sql.SQLException;      public class GradeDAO {       public Grade QueryGradeSnumAndCid(String snum, String cid) {           //如果查询不到就是为null           Grade grade = null;           try {               //定义SQL语句               String sql = "select s.stu_num snum,s.stu_name sname,c.course_id cid,c.course_name cname ,g.score score from students s INNER JOIN grades g INNER JOIN courses c  on s.stu_num = g.snum and g.cid = c.course_id where s.stu_num=? and c.course_id=?";               //查询               QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());               grade = queryRunner.query(sql,new BeanHandler<Grade>(Grade.class),snum,cid);           }catch (Exception e){               e.printStackTrace();           }           //返回结果           return grade;       }   } 

4.3.3实现LoginPageServlet登录界面

  • 编写动态网页发送信息

    package Servlets;  import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;  import java.io.IOException; import java.io.PrintWriter;  @WebServlet("/login") public class LoginPageServlet extends HttpServlet {     @Override     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {     }     @Override     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         super.doGet(req, resp);         //响应一个登录界面         //设置响应信息         response.setStatus(200);         response.setContentType("text/html;charset=utf-8");         response.setCharacterEncoding("utf-8");          //输出         PrintWriter out = response.getWriter();         out.println("<!DOCTYPE html>");         out.println("<html>");         out.println("<head>");         out.println("<meta charset='utf-8'>");         out.println("<title>学生成绩查询系统-登录</title>");         out.println("</head>");         out.println("<body>");         //发送到CheckStudent这个页面,让CheckStudent页面验证          out.println("<form action='CheckStudent' method='post'>");         out.println("<h3>学生成绩查询系统—学生登录</h3>");         out.println("<p>学号:<input type='text' name='stuNum' placeholder='学生学号'/></p>");         out.println("<p>密码:<input type='password' name='stuPwd' placeholder='登录密码'/></p>");         out.println("<p><input type='submit' value='登录'/></p>");         out.println("</form>");         out.println("</body>");         out.println("</html>");         //刷新关闭         out.flush();         out.close();     } } 

4.3.4实现CheckServlet验证登录

  • 验证登录信息

    package Servlets;  import dao.StudentDAO; import dto.Student; import jakarta.servlet.*; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;  import java.io.IOException;  @WebServlet("/CheckServlet") public class CheckServlet extends HttpServlet {     @Override     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {     }     @Override     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //接收学号和密码         //设置编码         request.setCharacterEncoding("utf-8");         //账户         String num = request.getParameter("stuNum");         //密码         String pwd = request.getParameter("stuPwd");          //调用studentDAO中的方法,根据学号和密码查询学生信息是否存在         StudentDAO studentDAO = new StudentDAO();         Student student = studentDAO.QueryStudentNumAndPwd(num, pwd);                  //判断查询结果,响应客户端 //根据登录验证的不同结果响应给客户端不同的页面 if(student == null){     //登录失败:响应客户端登录页面,提示“登录失败,学号或密码错误!”      //转发到下一个Servlet是可以通过request传递数据过去的     request.setAttribute("tips","登录失败,学号或密码错误!");     //转发到LoginPageServlet:在当前Servlet类的doPost方法转到,也会转发到下一个Servelt的doPost     request.getRequestDispatcher("login").forward(request,response); }else{     //登录成功:响应客户端系统的主页     //重定向到IndexPageServlet:无需传递参数到IndexPageServlet,所以我们可以使用重定向     response.sendRedirect("IndexPageServlet"); } } } 

4.3.5实现IndexPageServlet主页面

  • 显示成绩查询的主页面,并且能够输入学号和课程号查询成绩

    package Servlets;  import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;  import java.io.IOException; import java.io.PrintWriter;  @WebServlet("/IndexPageServlet") public class IndexPageServlet extends HttpServlet {     @Override     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //响应一个登录界面         //设置响应信息         response.setStatus(200);         response.setContentType("text/html;charset=utf-8");         response.setCharacterEncoding("utf-8");          //输出          PrintWriter out = response.getWriter();         out.println("<!DOCTYPE html>");         out.println("<html>");         out.println("<head>");         out.println("<meta charset='utf-8'>");         out.println("<title>学生成绩查询系统-主页面</title>");         out.println("</head>");         out.println("<body>");         out.println("<table border='1' width='100%' height='700'>");         out.println("<tr height='100'><td colspan='2'><label>学生成绩查询系统欢迎您!</label></td></tr>");         out.println("<tr>");         out.println("<td width='200'>2-1</td>");         out.println("<td align='center' valign='top'>");         //跳转到GradeQueryServlet类         out.println("<form action='GradeQueryServlet' method='post'>");             out.println("<h3>查询成绩</h3>");             out.println("<p>学号:<input type='text' name='stuNum' placeholder='学生学号'/></p>");             out.println("<p>课程:<input type='text' name='courseId' placeholder='课程编号'/></p>");             out.println("<p><input type='submit' value='查询'/></p>");             out.println("</form>");         out.println("</td>");         out.println("</tr>");         out.println("</table>");         out.println("</body>");         out.println("</html>");         //关闭         out.flush();         out.close();     }      @Override     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {     } }  

4.3.6登录失败转发到LoginPageServlet

  • CheckServlet转发到LoginPageServlet,并传递参数

    //3.判断查询结果,响应客户端 //根据登录验证的不同结果响应给客户端不同的页面 if(student == null){     //登录失败:响应客户端登录页面,提示“登录失败,学号或密码错误!”      //转发到下一个Servlet是可以通过request传递数据过去的     request.setAttribute("tips","登录失败,学号或密码错误!");     //转发到LoginPageServlet:在当前Servlet类的doPost方法转到,也会转发到下一个Servelt的doPost     request.getRequestDispatcher("login").forward(request,response); }else{     //登录成功:响应客户端系统的主页      } 

    LoginPageServlet接收参数响应登录页面

    package Servlets;  import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;  import java.io.IOException; import java.io.PrintWriter;  @WebServlet("/login") public class LoginPageServlet extends HttpServlet {     @Override     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //doPost调用doGet         doGet(request,response);     }     @Override     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //接收从CheckServlet传递的提示信息         String tips = (String) request.getAttribute("tips");          //响应一个登录界面         //设置响应信息         response.setStatus(200);         response.setContentType("text/html;charset=utf-8");         response.setCharacterEncoding("utf-8");          //输出         PrintWriter out = response.getWriter();         out.println("<!DOCTYPE html>");         out.println("<html>");         out.println("<head>");         out.println("<meta charset='utf-8'>");         out.println("<title>学生成绩查询系统-登录</title>");         out.println("</head>");         out.println("<body>");         if(tips != null) {             out.println("<label style='color:red'>" + tips + "</label>");             //发送到CheckStudent这个页面,让CheckStudent页面验证             out.println("<form action='CheckStudent' method='post'>");             out.println("<h3>学生成绩查询系统—学生登录</h3>");             out.println("<p>学号:<input type='text' name='stuNum' placeholder='学生学号'/></p>");             out.println("<p>密码:<input type='password' name='stuPwd' placeholder='登录密码'/></p>");             out.println("<p><input type='submit' value='登录'/></p>");             out.println("</form>");             out.println("</body>");             out.println("</html>");             //刷新关闭             out.flush();             out.close();          }     } } 

4.3.7登录成功重定向IndexPageServlet

  • CheckServlet重定向IndexPageServlet

    //3.判断查询结果,响应客户端 //根据登录验证的不同结果响应给客户端不同的页面 if(student == null){     //登录失败:响应客户端登录页面,提示“登录失败,学号或密码错误!”      //转发到下一个Servlet是可以通过request传递数据过去的     request.setAttribute("tips","登录失败,学号或密码错误!");     //转发到LoginPageServlet:在当前Servlet类的doPost方法转到,也会转发到下一个Servelt的doPost     request.getRequestDispatcher("login").forward(request,response); }else{     //登录成功:响应客户端系统的主页     //重定向到IndexPageServlet:无需传递参数到IndexPageServlet,所以我们可以使用重定向     response.sendRedirect("IndexPageServlet"); } 

4.3.8实现GradeQueryServlet查询成绩

  • GradeQueryServlet接收客户端输入的学号、课程ID,查询成绩

    package Servlets;  import dao.GradeDAO; import dto.Grade; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse;  import java.io.IOException;  @WebServlet("/GradeQueryServlet") public class GradeQueryServlet extends HttpServlet {     @Override     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //接收浏览器输入的学号和课程id         String snum = request.getParameter("stuNum");         String cid = request.getParameter("courseId");         //调用gradeDAO中的方法看是否匹配并且查询创建         GradeDAO gradeDAO = new GradeDAO();         Grade grade = gradeDAO.QueryGradeSnumAndCid(snum, cid);         //查询到成绩之后,将成绩传递到GradePageServlet         //由GradePageServlet响应给浏览器一个页面,并把成绩显示出来         request.setAttribute("grage",grade);         request.getRequestDispatcher("GradePageServlet").forward(request,response);     }      @Override     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //如果允许客户端get和post方式提交,我们可以在doGet中调用doPost,业务代码写在doPost         doPost(request,response);     } }  

4.3.9实现GradePageServlet显示成绩

  • GradePageServle响应给客户端一个成绩结果页面,并显示成绩

    package com.qfedu.sgms.servlets;  import com.qfedu.sgms.dto.Grade;  import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;  /**  * @Description 成绩查询结果页面  * @Author 千锋涛哥  * 公众号: Java架构栈  */ @WebServlet("/GradePageServlet") public class GradePageServlet extends HttpServlet {      @Override     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         doPost(request, response);     }      @Override     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {         //1.接收转发时传递的成绩         Grade grade = (Grade) request.getAttribute("grade");          //2.设置响应头         response.setStatus(200);         response.setContentType("text/html;charset=utf-8");         response.setCharacterEncoding("utf-8");          //3.响应成绩结果页面         PrintWriter out = response.getWriter();         out.println("<!DOCTYPE html>");         out.println("<html>");         out.println("<head>");         out.println("<meta charset='utf-8'>");         out.println("<title>学生成绩查询系统</title>");         out.println("</head>");         out.println("<body>");         out.println("<table border='1' width='100%' height='700'>");         out.println("<tr height='100'><td colspan='2'><label>学生成绩查询系统欢迎您!</label></td></tr>");         out.println("<tr>");         out.println("<td width='200'>2-1</td>");         out.println("<td align='center' valign='top'>");             //查询成绩的表单 : 修改action属性为 GradeQueryServlet             out.println("<h3>查询结果</h3>");             if(grade != null){                 out.println("<table width='200' border='1' cellspacing='0'>");                 out.println("<tr><td>学号</td><td>"+grade.getSnum()+"</td></tr>");                 out.println("<tr><td>姓名</td><td>"+grade.getSname()+"</td></tr>");                 out.println("<tr><td>课程ID</td><td>"+grade.getCid()+"</td></tr>");                 out.println("<tr><td>课程名</td><td>"+grade.getCname()+"</td></tr>");                 out.println("<tr><td>成绩</td><td><label style='color:red;font-weight:bold'>"+grade.getScore()+"</label></td></tr>");                 out.println("</table>");             }else{                 out.println("<label style='color:red;font-weight:bold;font-size:20px'>学号或课程号有误!</label>");             }             out.println("<a href='IndexPageServlet'>继续查询</a>");         out.println("</td>");         out.println("</tr>");         out.println("</table>");         out.println("</body>");         out.println("</html>");         out.flush();         out.close();     } } 
请发表您的评论
请关注微信公众号
微信二维码
不容错过
Powered By Z-BlogPHP