Servlet核心
1.核心类与接口
-
init:完成初始化操作
-
只会执行一次
-
没有配置
1 时才只会执行一次 -
在实例类对象中配置(注解方式)
@WebServlet(vlue="路径",loadonstartup=1)
-
如果有多个service配置了loadonstartup,里面的数字就是在服务器中创建示例的顺序
-
-
init方法在执行的时候,对象已经被创建出来了
-
-
service:处理用户请求的核心方法
- 用户每发送一次请求,server方法就会执行进行
-
doGet,doPost:根据客户端的请求方式,如果是get则调用doGet,如果是post则调用doPost.....
-
destroy:Tomcat服务器在销毁对象之前,会调用一次destroy方法
- 只会执行一次
- destroy方法执行的时候,对象的内存还没有被销毁,即将被销毁
- destroy方法中可以编写销毁前的准备
-
编写一个抽象类,有一个抽象方法service
-
实现servlet接口
-
以后编写的所有servlet类都继承这个抽象类,重写service方法即可
-
-
执行流程
- 按照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对象
-
接收请求行数据
- 获取请求方式
- request.getMethod();
- 获取请求url
- request.getRequestURL();
- 获取请求url上的参数
- request.getParameter("值");
- 获取请求协议
- request.getProtocol();
- 获取请求方式
-
接收请求头数据
- 获取请求头中所有的key
- request,getHeaderNames();
- 返回的值是枚举
- 获取请求头中对应的key
- request,getHeader("值");
- 获取请求头中所有的key
-
接收请求正文数据
-
获取请求正文
-
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对象
-
设置响应状态行
- 设置状态中的状态码
- response.setStatus(数字);例200
- 设置状态中的状态码
-
设置响应头
-
设置响应客户端的数据格式
- response.setContentType("数据格式");例text/html
-
设置响应客户端的数据长度
- response.setContentLength(数字);例1024
-
设置其他的响应头属性
-
response.setHeader("属性",格式);
-
//例 response.setHeader("ContentType","text/html"); //等价于 response.setContentType("text/html");
-
-
-
设置响应正文
- 设置响应客户端的数据编码格式
- response.setCharacterEncoding("编码格式");例utf-8
- 设置响应客户端的数据编码格式
4.Servlet练习
4.1环境准备
-
创建一个java web工程
- 右击模块->选择Add Framework Support..
- javaEE中选择Web Application
- 默认为4.0版本和创建一个web.xml文件
- 默认生成一个web目录(就是项目的名字)
-
搭建jdbc环境
-
导入jdbc所需的驱动jar包,数据库连接池jar包,DBUtils.jar包
-
在web-inf中新建一个lib目录,全小写
-
将jar包放入进来
-
添加到模块
-
-
配置连接池信息
-
在项目中新建一个properties文件存放连接池信息
-
# 数据库连接池信息 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
-
-
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; } }
-
-
数据库环境准备
-
-- 学生信息表 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练习要求
- 根据项目业务流程图,完成需要数据库操作
- 学生登录实现:
根据输入的学号和密码查询学生信息
,如果查询到了说明学号密码输入正确,登录成功;根据输入的学号查询学生
,如果查询到了说明学号正确,再比较输入的密码和查询出来的密码是否一致,如果一致则登录成功;
- 查询成绩:
- 根据学号和课程号从成绩表中查询成绩
- 学生登录实现:
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 Servlets;
import dto.Grade;
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("/GradePageServlet")
public class GradePageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws 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();
}
}
标签:servlet,request,println,import,javaweb2,response,out
From: https://www.cnblogs.com/Myvlog/p/16923844.html