Servlet
Servlet是Java提供的一门动态的web资源开发技术
servlet是javaEE规范之一,其实就是一个接口,将来我们需要定义servlet类实现servlet接口,并由web服务器运行servlet
快速入门
创建web项目,导入servlet依赖坐标
x1<dependency>2<groupId>javax.servlet</groupId>3<artifactId>javax.servlet-api</artifactId>4<version>3.1.0</version>5<scope>provided</scope>6</dependency>7创建:定义一个类,实现servlet接口,并重写接口中的方法,并在servlet方法中输入一句话
xxxxxxxxxx31public class ServletDemo implements Servelt{2public void service(){}3}配置:在类上使用@WebServlet注解,配置该Servlet的访问路径
xxxxxxxxxx312("/deno")3public class ServletDemo implements Servelt{}访问:启动Tomcat,浏览器输入URL访问Servlet
xxxxxxxxxx11http://localhost:80/web-demo/demo1
servlet执行流程
Servlet由web服务器创建,Servlet方法由web服务器调用。
servlet生命周期
生命周期:一个对象从被创建到被销毁的过程
servlet体系结构
Servlet体系结构
Servlet ——Servlet体系根接口
GenneriServlet——Servlet抽象实现类
HttpServlet——对HTTP协议封装的Servlet是实现类
开发B/S架构的web项目都是正对http协议的,所以自定义servlet会继承HttpServlet
xxxxxxxxxx131
2("/demo")3public class ServletDemo extends HttpServlet{4 5 6 protected void doGet(HttpServletRequest req,HttpServletResponse resp){7 //TODO Get请求方式的处理逻辑8 }9 10 protected void doPost(HttpServletRequest req,HttpServletResponse resp){11 //TODO Post请求方式的处理逻辑12 }13}get和post请求方式是在表单里面设置的,默认是get请求方式
需要根据请求方式的不同分别进行处理
先后获取请求方式
HttpServletRequest request= (HttpServletRequest) servletRequest;//强制类型转换
String method=request.getMethod();//获取请求方式
判断
//对获取的method进行判断
if(“GET”.equals(method)){
// get请求的处理方式
}else if(“POST”.equals(method)){
// post请求的处理方式
}
HttpServlet的使用步骤
继承HttpServlet
重写doGet和doPost方法
HttpServlet原理
获取请求方式,并根据不同的请求方式调用不同的方法
Servlet的方法
初始化方法,在Servlet被创建时执行,只执行一次
void init(ServletConfig config)
提供服务的方法,每次Servlet被访问都会调用该方法
void service(ServletRequest req,ServletResponse res)
销毁方法,当servlet被销毁时,调用该方法,在内存释放或服务器关闭时销毁servlet
void destroy()
获取ServletConfig对象
ServletConfig getServletConfig()
获取Servlet信息
String getServletInfo()
xxxxxxxxxx321package com.ldb.note;2
3import javax.servlet.*;4import java.io.IOException;5
6public class HelloServletDemo2 implements Servlet {7 8 public void init(ServletConfig servletConfig) throws ServletException {9 10 }11
12 13 public ServletConfig getServletConfig() {14 return null;15 }16
17 18 public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {19
20 }21
22 23 public String getServletInfo() {24 return null;25 }26
27 28 public void destroy() {29
30 }31}32
servlet urlPattern配置
servlet要想被访问,必须配置访问路径(urlPattern)
一个Servlet,可以配置多个urlPattern
@WebServlet(urlPattern={“/demo1”,”/demo2”})
usrPattern配置规则
精确匹配
目录匹配
扩展名匹配
任意匹配
XML配置方式编写servlet
servlet从3.0开始支持使用注解配置
步骤
编写servlet类
在web.xml中配置该Servlet
xxxxxxxxxx81<servlet>2<servlet-name>demo</servlet-name>3<servlet-class>com.ldb.web.servlet.servletDemo</servlet-class>4</servlet>5<servlet-mapping>6<servlet-name>demo</servlet-name>7<url-pattern>/demo</url-pattern>8</servlet-mapping>
Request和Response
Request(请求)——获取请求数据
Response(响应)——设置响应数据
使用Request对象获取请求数据
String name=request.getParameter(“name”);——这样就获取了表单里面input输入的内容,input标签需要设置name属性和属性值,Request对象里的方法里填写的就是input标签设置的那么属性的属性值
使用Response对象设置响应的数据
response.setHeader(“content-type”,”text/html;charset=utf-8“);//设置页面的编码格式
response.getWrite().write(“
”+name+“
”);在空白的页面上写上标签,获取的表单值也在页面上显示
Request
Request继承体系
ServletRequest是Java提供的请求对象根接口
HttpServletRequest是java提供的http协议封装的请求对象接口
RequestFacade是Tomcat定义的实现类
Tomcat需要解析请求数据,封装为request对象,并且request对象传递到service方法中
使用request对象,查阅javaEE API文档的HttpServletRequest接口
Request获取请求数据
请求数据分为3部分:
请求行——
GET/request-demo/req1?username=zhangHTTP/1.1String getMethod():获取请求方式:GET
String getContextPath():获取虚拟目录(项目的访问路径):/request-demo
StringBuffer getRequestURL():获取URL:
http://localhost:8080/request-demo/req1String getRequestURI():获取URI(统一资源标识符):/request-demo/req1
String getQueryString():获取请求参数(GET方式):username=zhang
xxxxxxxxxx1312String method = req.getMethod();3String contextPath = req.getContextPath();4StringBuffer requestURL = req.getRequestURL();5String requestURI = req.getRequestURI();6String queryString = req.getQueryString();7PrintWriter out = resp.getWriter();8out.println("<h1>"+method+"</h1>");9out.println("<h1>"+contextPath+"</h1>");10out.println("<h1>"+requestURL+"</h1>");11out.println("<h1>"+requestURI+"</h1>");12out.println("<h1>"+queryString+"</h1>");13请求头——
User-Agent:Mozilla/5.0 Chrome/91.0.4472.106String getHeader(String name):根据请求头名称获取值
请求体——只有post请求才有请求体
username=123456&password=23456ServletInputStream getInputStream():获取字节输入流(post请求方式)
BufferedReader getReader():获取字符输入流(post请求方式)
Request通用方式获取请求参数
get和post都可以使用的获取请求参数的方式:
xxxxxxxxxx111
2String method=this.getMethod();//获取请求方式3
4if("GET".equals(method)){5 params=this.getQueryString();6 7}else if("POST".equals(method)){8 9 BufferedReader reader = this.getReader();10 params=reader.readLine();11}xxxxxxxxxx1812<html lang="en">3<head>4 <meta charset="UTF-8">5 <title>Title</title>6 <link rel="stylesheet" href="index.css">7</head>8<body>9<form action="servlet-demo" method="post" id="formLogin">10 <input type="text" name="user" placeholder="输入您的账号">11 <input type="password" name="pass" placeholder="输入您的密码">12 <input type="checkbox" name="hobby" value="1">游泳13 <input type="checkbox" name="hobby" value="2">爬山14 <input type="checkbox" name="hobby" value="3">跑步15 <button type="submit">登录</button>16</form>17</body>18</html>
Map<String,String[ ]>getParameterMap();——获取所有参数Map集合
xxxxxxxxxx101Map<String, String[]> map = req.getParameterMap();2for (String i : map.keySet()) {3System.out.print(i+":");4String[ ] values = map.get(i);5for (String value : values) {6System.out.print(value+" ");7}8System.out.println();910}
String[ ] getParameterValues(String name);——根据名称获取具体的参数值(数组)(即form表单里面name的属性值进行获取对应值)
xxxxxxxxxx512String[] hobbies = req.getParameterValues("hobby");3for (String h : hobbies) {4System.out.println(h);5}String getParameter(String name):——根据name属性值进行获取对应的具体值,单个参数值
xxxxxxxxxx412String username = req.getParameter("user");3System.out.println(username);4
以上三种获取请求参数都适用于get和post请求方式
xxxxxxxxxx51//如果要想在另一个请求方式里使用当前请求方式的代码,则在另一个请求方法里使用如下代码2this.doPost(req,resp);//当请求方式是post时在get方法里使用3//或4this.doGet(req,resp);//当请求方式是gett时在get方法里使用5
解决中文乱码的问题
xxxxxxxxxx111//在两个请求方法中添加如下代码2
3
4resp.setContentType("text/html;charset=utf-8");5 req.setCharacterEncoding("utf-8");//get请求方式6
7//--------------------------------------------------------------------------------//8
9//post请求只需要这一行代码10 resp.setCharacterEncoding("utf-8");//其实就是设置字符输入流的编码post请求方式11
xxxxxxxxxx101
2
3 String user="张三"'';41. URL编码——将中文编码成乱码5 String encode=URLEncoder.encode(user,"utf-8");6 System.out.println(encode);72. URL解码——将乱码解码成中文8 String dncode=URLDecoder.encode(encode,"utf-8");9 System.out.println(dncode);10
这一行代码可以直接解决乱码问题:GET请求只有这种方式进行解决乱码的问题
usename=new String(usename.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
Request请求转发
请求转发(forward):是一种在服务器内部的资源跳转方式
实现方式:
req.getRequestDispatcher(“资源B路径”).forward(req,resp);
请求转发资源间共享数据:使用Request对象
void setAttribute (String name,Object o):存储数据到request域中
在跳转的servlet里设置
req.setAttribute("msg","我是你爸爸");
req.getRequestDispatcher(“/servlet-demo”).forward(req,resp);
// 另一个servlet中获取数据 Object msg = req.getAttribute("msg");
System.out.println(msg);
Object getAttribute(String name):根据key,获取值
void removeAttribute(String name):根据key,删除该键值对
请求转发的特点
浏览器地址栏不发生改变
只能转发到当前服务器的内部资源
一次请求,可以在转发的资源间使用request共享数据
Response
response:使用response对象来设置响应数据
Response的体系结构和Request一样
ServletRequest是Java提供的请求对象根接口
HttpServletRequest是java提供的http协议封装的请求对象接口
RequestFacade是Tomcat定义的实现类
Response设置响应数据功能介绍
响应数据分为3部分:
响应行:
HTTP/1.1 200 OKvoid setStatus(int sc):设置响应状态码
响应头:
Content-Type:text/htmlvoid setHeader(String name,String value):设置响应头键值对
响应体:
<html><head><body></body></head></html>PrintWriter getWriter():获取字符输出流
ServletOutputStream getOutputStream():获取字节输出流
Response完成重定向
重定向(Redirect):一种资源跳转方式
浏览器请求资源A,资源A处理不了,报状态码302,提示浏览器请求到资源B进行处理,并将资源B的位置告知浏览器响应头:location:资源B的路径
实现方式
resp.setStatus(302);
resp.setHeader(“location”,“虚拟目录/资源B的路径”)//location是固定的
—————简化重新向———————————–
response.sendRedirect("虚拟目录/资源B的路径");
重定向的特点(与请求转发完全相反)
浏览器地址栏发生变化
可以重定向到任意位置的资源(服务器内部、外部均可)
两次请求,不能在多个资源使用request共享数据
路径问题
明确路径使用者
浏览器使用:需要加虚拟目录
服务器使用:不需要加虚拟目录
动态获取虚拟目录
String contextPath=request.getContextPath();
response.sendRedirect(contextPath+"/资源B的路径");
Response响应字符数据
使用
通过Response对象获取字符输出流
PrintWriter write=resp.getWriter();
写数据
write.write(“
<a href='https://www.baidu.com/'>百度</a>>”);——可以写一些html的标签和纯文本,要写html标签必须要设置response.setContentType("text/html;charset=utf-8");
流不需要关闭,随着response对象的销毁,由服务器关闭
response.setContentType("text/html;charset=utf-8");——设置响应的数据格式和字符集
Response响应字节数据
使用
通过Response对象获取字符输出流
ServletOutputStream outputStream=resp.getOutputStream();
写数据
outputStream.write(字节数据);
使用工具类IOUtils
导入坐标
xxxxxxxxxx51<dependency>2<groudId>commons-io</groudId>3<artifactld>commons-io</artifactld>4<version>2.6</version>5</dependency>使用
xxxxxxxxxx312IOUtils.copy(输入流,输出流);3
response可以抓取图片等媒体数据,注意的是不要改变写入的ContentType的类型,即不使用response.setContentType("txt/html;charset=utf-8");否则图片会变成乱码
xxxxxxxxxx111
2// 读取文件3 FileInputStream file = new FileInputStream("D://NOTE//src//main//java//aaa.jpg");4
5// 获取字节输出流6 ServletOutputStream os = response.getOutputStream();7
8// 完成流的复制9 IOUtils.copy(file,os);//使用commit-io包可以直接这样写就能将一张图片写入浏览器10 file.close();11
案例——登录和注册
登录和注册HTML页面
xxxxxxxxxx251
23<html lang="en">4<head>5 <meta charset="UTF-8">6 <title>Title</title>7 <link rel="stylesheet" href="index.css">8</head>9<body>10<form action="/NOTE/Login" method="get" id="formLogin">11 <input id="user" type="text" name="user" placeholder="输入您的账号">12 <input id="password" type="password" name="pass" placeholder="输入您的密码">13 <button id="login" type="button">登录</button>14 <button id="register" type="button">注册</button>15</form>16<form action="/NOTE/Register" method="get" id="formRegister">17 <input id="setUser" type="text" name="user" placeholder="设置账号">18 <input id="setPassword" type="password" name="pass" placeholder="设置密码">19 <button id="create" type="button">注册</button>20 <button id="clean" type="reset">清除</button>21</form>22</body>23<script src="jQuery.min.js"></script>24<script src="index.js"></script>25</html>实体类文件
xxxxxxxxxx321
2package com.UserMapper;3//实体类4public class User {5 private Integer id;6 private String password;7
8 9 public String toString() {10 return "User{" +11 "id=" + id +12 ", password='" + password + '\'' +13 '}';14 }15
16 public Integer getId() {17 return id;18 }19
20 public void setId(Integer id) {21 this.id = id;22 }23
24 public String getPassword() {25 return password;26 }27
28 public void setPassword(String password) {29 this.password = password;30 }31}32
登录提交的servlet代码
xxxxxxxxxx611
2package com.ldb.note;3
4import com.Mapper.userMapper;5import com.UserMapper.User;6import org.apache.ibatis.io.Resources;7import org.apache.ibatis.session.SqlSession;8import org.apache.ibatis.session.SqlSessionFactory;9import org.apache.ibatis.session.SqlSessionFactoryBuilder;10
11import javax.servlet.annotation.WebServlet;12import javax.servlet.http.HttpServlet;13import javax.servlet.http.HttpServletRequest;14import javax.servlet.http.HttpServletResponse;15import java.io.IOException;16import java.io.InputStream;17import java.io.PrintWriter;18// 登录页面19("/Login")20public class Login extends HttpServlet {21 22 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {23 response.setContentType("text/html;charset=utf-8");24 // 接收用户信息25 int user = Integer.parseInt(request.getParameter("user"));26 String pass = request.getParameter("pass");27
28// 调用mybatis完成查询:29// 获取SqlSessionFactory对象30 String resource = "mybatis-config.xml";31 InputStream inputStream = Resources.getResourceAsStream(resource);32 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);33// 获取对应的SqlSession对象34 SqlSession session = sqlSessionFactory.openSession();35// 获取Mapper36 userMapper mapper = session.getMapper(userMapper.class);37// 调用方法38 User u = mapper.select(user, pass);39// 释放资源40 session.close();41
42 PrintWriter writer = response.getWriter();43// 判断user是否weinull44 if(u!=null){45// 登录成功46 writer.write("<h1>登录成功</h1>");47
48 }else {49// 登录失败50 writer.write("<h1>登录失败</h1>");51 }52
53 }54
55 56 protected void doPost(HttpServletRequest request, HttpServletResponse response) {57
58
59 }60}61
注册servlet代码
xxxxxxxxxx641package com.ldb.note;2
3import com.Mapper.userMapper;4import com.UserMapper.User;5import org.apache.ibatis.io.Resources;6import org.apache.ibatis.session.SqlSession;7import org.apache.ibatis.session.SqlSessionFactory;8import org.apache.ibatis.session.SqlSessionFactoryBuilder;9
10import javax.servlet.*;11import javax.servlet.http.*;12import javax.servlet.annotation.*;13import java.io.IOException;14import java.io.InputStream;15//注册页面16("/Register")17public class Register extends HttpServlet {18 19 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {20 System.out.println("register");21
22 response.setContentType("text/html;charset=utf-8");23 // 接收用户信息24 int user = Integer.parseInt(request.getParameter("user"));25 String pass = request.getParameter("pass");26
27// 封装用户对象28 User u =new User();29 u.setId(user);30 u.setPassword(pass);31 System.out.println(u);32// 调用mybatis完成查询:33// 获取SqlSessionFactory对象34 String resource = "mybatis-config.xml";35 InputStream inputStream = Resources.getResourceAsStream(resource);36 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);37// 获取对应的SqlSession对象38 SqlSession session = sqlSessionFactory.openSession();39// 获取Mapper40 userMapper mapper = session.getMapper(userMapper.class);41// 调用方法42 User user1 = mapper.selectByuserID(user);43 if(user1==null){44 mapper.insert(u);45// 提交事务——切记不要忘了这一步46 session.commit();47
48 String contextPath=request.getContextPath();49 response.sendRedirect(contextPath+"/index.html");50 System.out.println("注册成功");51 }else {52 System.out.println("用户已存在");53 }54
55
56 }57
58 59 protected void doPost(HttpServletRequest request, HttpServletResponse response) {60
61
62 }63}64
Mapper接口文件
xxxxxxxxxx251
2package com.Mapper;3
4import com.UserMapper.User;5import org.apache.ibatis.annotations.Insert;6import org.apache.ibatis.annotations.Param;7import org.apache.ibatis.annotations.Select;8
9public interface userMapper {10// 进行用户——根据账号和密码查询用户对象11 ("select*from userid where id=#{id} and password=#{password}")12 User select(("id") int id, ("password") String password);13
14
15
16 // 用户注册17 // 先检查用户id是否存在18 ("select *from userid where id = #{id}")19 User selectByuserID(int id);20
21// 添加新的用户22 ("insert into userid values (#{id},#{password})")23 void insert(User user);24}25
sql映射文件
xxxxxxxxxx91
2 34 5 6<mapper namespace="com.Mapper.userMapper">7
8
9</mapper>mybatis配置文件
xxxxxxxxxx211 23 4 5<configuration>6 <environments default="development">7 <environment id="development">8 <transactionManager type="JDBC"/>9 <dataSource type="POOLED">10 <property name="driver" value="com.mysql.cj.jdbc.Driver"/>11 <property name="url" value="jdbc:mysql:///login?useSSL=false&useServerPrepStmts=true"/>12 <property name="username" value="root"/>13 <property name="password" value="LDBISABOY1314"/>14 </dataSource>15 </environment>16 </environments>17 <mappers>18<!-- 扫描mapper文件-->19 <package name="com.Mapper"/>20 </mappers>21</configuration>问题
代码重复
SqlSessionFactory工厂只能创建一次,不要重复创建,在login和register两个servlet文件中都创建这个工厂了,这样是不行的,会消耗内存,所以需要进一步优化
优化:创建一个工具类
xxxxxxxxxx291
2package com.utils;3
4import org.apache.ibatis.io.Resources;5import org.apache.ibatis.session.SqlSessionFactory;6import org.apache.ibatis.session.SqlSessionFactoryBuilder;7
8import java.io.IOException;9import java.io.InputStream;10
11public class SqlSessionFactoryUtils {12 private static SqlSessionFactory sqlSessionFactory;13 static {14// 静态代码块会随着类的加载会自动执行,且只执行一次15 try {16 String resource = "mybatis-config.xml";17 InputStream inputStream = Resources.getResourceAsStream(resource);18 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);19 } catch (IOException e) {20 e.printStackTrace();21 }22 }23
24 public static SqlSessionFactory getSqlSessionFactory(){25 return sqlSessionFactory;26 }27
28}29
要是使用这个工具类只需要在servlet文件将
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
替换成以下代码即可:
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();