Tomact和servlet快速入门教程
- tomcat的入门必备知识
-
- 1.下载:
- 2.安装: 解压压缩包即可
- 3.卸载: 删除目录即可
- 4.启动:
- 5.关闭:
- 6.部署:
-
- 静态项目和动态项目
- 将tomcat集成到IDEA中,并且创建JavaEE项目,部署项目
- Servlet
-
- web动态工程目录介绍
- 热部署
- 快速入门
- URL地址定位实现原理
- 生命周期方法
- 注解配置
-
- 步骤:
- IDEA与tomcat的相关配置
- Servlet的体系结构
- Servlet的urlpattern配置
- Http
-
- Http请求数据格式
- Request对象
-
- Request对象的继承体系结构
- Request的功能
-
- 获取请求行数据
- 获取请求头数据
- 获取请求体数据
- 获取请求参数的通用方式
-
- 根据参数名获取参数值:
- 根据参数名称获取参数值数组,多用于复选框:
- 获取所有请求的参数名称
- 获取所有参数的map集合
- 请求中的中文乱码问题
- 请求转发
-
- 步骤
- 共享数据(域对象)
- 获取ServletContext对象
- 用户登录案例
-
- 案例需求
- 案例分析
- 环境准备
-
- login.html中的form表单的action路径写法
- BeanUtils工具类,简化数据封装
-
- JavaBean: 标准的Java类
- 概念
- 方法
- HTTP响应消息
-
- 1. 响应行
- 2. 响应头
- 3. 响应空行
- 4. 响应体: 传输的数据
- Reponse对象
-
- 1.设置响应行
- 2.设置响应头
- 3.设置响应体
- 案例之完成重定向
-
- 简单的重定向写法:
- 重定向和转发的区别和各自特点
- 路径写法
-
- 路径分类
- 动态获取虚拟目录
- 服务器输出字符数据到浏览器
-
- 中文乱码问题
- 服务器输出字节数据到浏览器
- 字节输出流案例----验证码
- ServletContext对象
-
- 获取
- 功能
- 1.获取MIME类型
- 2.域对象,共享数据
- 3.获取文件服务器路径
- 文件下载案例
-
- 中文文件名问题
tomcat的入门必备知识
1.下载:
tomcat官网下载地址
2.安装: 解压压缩包即可
注意:安装目录建议不要有中文和空格
3.卸载: 删除目录即可
4.启动:
4.1 bin/startup.bat ,双击运行该文件即可
4.2 访问:浏览器输入: http://localhost:8080 回车访问自己
或者 http://别人的ip:8080 访问别人
可以通过ipconfig:查看本机ip地址
4.3 启动可能出现的问题:
4.3.1 黑窗口一闪而过:
原因: 没有正确配置JAVA_HOME环境变量
4.3.2 启动报错:
原因: 端口号被占用
推荐的解决方法1: 找到占用的端口号,并且找到对应的进行,杀死该进程
在cmd窗口输入netstat -ano
打开任务管理器,找到刚才的进程ID,然后结束该进程
解决方法2: 修改自身端口号
conf/server.xml用记事本打开,将其默认端口号修改即可,可能还需要连带着修改其他的相关默认端口号才行
一般会把tomcat的默认端口号修改为80.
80端口号是http协议的默认端口号
好处:在访问时,就不需要输入端口号了
5.关闭:
强制关闭: 点击窗口的x
正常关闭: bin/shutdown.bat
或者ctrl+c
6.部署:
部署方式:
1.直接将项目放到webapps目录下即可
/hello: 项目的访问路径---->虚拟目录
简化部署:将项目打包成一个war包,再将war包部署到webapps目录下面
war包会自动解压缩.
2.配置conf/server.xml文件
在< Host >标签体中配置
<Context docBase="D:\hello" path="/hehe" />
docBase: 项目存放的路径
path: 虚拟目录
3.在conf\Catalina\localhost创建了一个任意名称的xml文件。
在文件中编写:
<Context docBase="D:\hello"/>
虚拟目录就是xml文件的名称
静态项目和动态项目
目录结构:
java动态项目的目录结构:
-项目根目录
–WEB-INF目录:
— web.xml: web项目的核心配置文件
—classes: 放置字节码文件的目录
—lib目录: 放置依赖的jar包
将tomcat集成到IDEA中,并且创建JavaEE项目,部署项目
tomcat集成到IDEA的教程
Servlet
概念:运行在服务器端的小程序
Servlet就是一个接口,定义了Java类被浏览器访问到的(tomcat)规则
将来我们自定义一个类,实现Servlet接口,复写方法
web动态工程目录介绍
热部署
Tomcat上的部署问题,有时候也是个麻烦的问题,要是不采用热部署,我们就只能每次对原来的文件做一次改动的时候就要重新部署,而每次重新部署都要关闭tomcat,部署完重启tomcat,可见这是一个多么烦人的事情。现在,我们可以采用热部署了,以后,就不用做烦人的关闭重起工作。
热部署的设置:
快速入门
- 创建JavaEE项目
- 定义一个类,实现Servlet的接口
- 实现接口中的抽象方法
- 配置servler
在wed.xml的< web-app >标签里面进行配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置Servlet-->
<servlet>
<!--servlet-name标签Servlet程序起一个别名(一般是类名)-->
<servlet-name>demo1</servlet-name>
<!--servlet-class是servlet的全类名-->
<servlet-class>web.servlet.servletDemo</servlet-class>
</servlet>
<!--给servlet程序配置访问地址-->
<servlet-mapping>
<!--告诉服务器,我当前配置的地址给哪个servlet程序使用-->
<servlet-name>demo1</servlet-name>
<!--配置访问地址
/ 斜杠在服务器解析的时候表示地址为: http://ip:port/工程路径
/demo1 表示地址为: http://ip:port/工程路径/demo1
-->
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
</web-app>
常见错误:
url-pattern配置的路径中没有以斜杠打头
servlet-name配置的值不存在
servlet-class标签全类名配置错误
工程路径名修改:
URL地址定位实现原理
执行原理:
1.当服务器接收到客户端的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2.查找web.xml文件,看是否有对应的< url-pattern >标签内容体
3.如果有,则在找到对应的< servlet-class >全类名
4.tomcat会将字节码文件加载进内存,并且创建其对象
5.调用其方法
生命周期方法
servlet中的生命周期:
- 被创建: 执行Init方法,只执行一次
- 提供服务: 执行service方法,执行多次
- 被销毁: 执行destory方法,只执行一次
Servlet的创建时机:
默认情况下,第一次被访问时,Servlet被创建
可以配置执行Sevlet的创建时机,如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置Servlet-->
<servlet>
<!--servlet-name标签Servlet程序起一个别名(一般是类名)-->
<servlet-name>demo1</servlet-name>
<!--servlet-class是servlet的全类名-->
<servlet-class>web.servlet.servletDemo</servlet-class>
<!-- 指定Servlet的创建时机
1.第一次被访问时,创建
<load-on-startup>的值为负数
2.在服务器启动时,创建
<load-on-startup>的值为0或者正整数
-->
<load-on-startup>5</load-on-startup>
</servlet>
<!--给servlet程序配置访问地址-->
<servlet-mapping>
<!--告诉服务器,我当前配置的地址给哪个servlet程序使用-->
<servlet-name>demo1</servlet-name>
<!--配置访问地址
/ 斜杠在服务器解析的时候表示地址为: http://ip:port/工程路径
/demo1 表示地址为: http://ip:port/工程路径/hello
-->
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
</web-app>
Servlet的init方法只执行一次,说明Servlet在内存中只存在一个对象,说明Servlet是单例的
- 多个对象同时访问时,可能存在线程安全问题
- 解决: 净量不要再Servlet中定义成员变量.即使定义了成员变量也不要修改其值
每次访问Servlet时,service方法都会被调用一次
Servlet被销毁时执行。服务器关闭时,Servlet被销毁。
只有服务器正常关闭时,才会执行destory
销毁方法在对象被销毁前执行
注解配置
Servlet 3.0以上才支持注解配置,支持注解配置后,就不需要web.xml了。
对于web.xml来说,对应的每一个servlet工程都需要重新配置一个web.xml太过繁琐
步骤:
- 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
- 定义一个类来实现Servlet的接口
- 复写方法
- 在类上使用@WebServlet注解,进行配置
注解就是加在类上面的,因此不需要关心全类名了,也就不需要再通过name属性做对应关系了
@WebServlet(urlPatterns="资源路径");
简化写法---->注解中最重要的属性value,其实就是urlPatterns属性,因此可以省略value
@WebServlet("资源路径");
IDEA与tomcat的相关配置
Servlet的体系结构
Servlet的urlpattern配置
1. urlpattern:servlet的访问路径
2.一个servlet可以定义多个访问路径: @WebServlet({"/Demo2","/dhy","/ly"})
3.路径定义规则:
1. /xxx
2. /xxx/xxx :多层路径,目录结构
- *.xxx
Servlet的url详解
Http
Http请求数据格式
Request对象
Request对象的继承体系结构
Request的功能
获取请求行数据
代码演示:
package request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/RequestServlet")
public class RequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取请求方式: GET
String method=request.getMethod();
System.out.println(method);
//2.获取虚拟目录: /demo2
String contextPath=request.getContextPath();
System.out.println(contextPath);
//3.获取servlet路径:/RequestServlet
String servletPath=request.getServletPath();
System.out.println(servletPath);
//4.获取get方式请求参数: name=dhy
String queryString=request.getQueryString();
System.out.println(queryString);
//5.获取请求URI: /demo2/RequestServlet
String requestURI=request.getRequestURI();
StringBuffer requestURL=request.getRequestURL();
System.out.println(requestURI);
System.out.println(requestURL);
//6.获取协议及版本: HTTP/1.1
String protocol=request.getProtocol();
System.out.println(protocol);
//7.获取客户机的IP地址
String remoteAddr=request.getRemoteAddr();
System.out.println(remoteAddr);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
获取请求头数据
获取所有头名称代码演示:
package request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/req")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求头数据
//1.获取所有请求头名称
Enumeration<String> headerNames=request.getHeaderNames();
//2.遍历
while(headerNames.hasMoreElements())
{
String name=headerNames.nextElement();
//更据名称获取请求头的值
String header=request.getHeader(name);
System.out.println(name+"------"+header);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
获取浏览器版本相关信息代码演示:
package request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/req")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示获取请求头数据: user-agent
String agent=request.getHeader("user-agent");//不区分大小写
//判断agent的浏览器版本:
if(agent.contains("Chrome"))
{
System.out.println("当前正在使用的是谷歌浏览器");
}
else if(agent.contains("Firefox"))
{
System.out.println("当前正在使用火狐浏览器");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
告诉服务器请求从哪里来—referer:
package request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/req")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示获取请求头数据: user-agent
//告诉服务器请求当前servlet实例的请求从哪里来的,是否来自指定网址
String referer=request.getHeader("referer");//不区分大小写
System.out.println(referer); // http://localhost:8080/demo2/login.html
//防止盗链
if(referer!=null)
{
if(referer.contains("/demo2"))
{
System.out.println("下面播放极限挑战");
}
else//盗链
System.out.println("请付费支持正版");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
获取请求体数据
代码演示:
package request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求消息体----请求参数
//1.获取请求字符流
BufferedReader br=request.getReader();
//2.读取数据
String line=null;
while((line=br.readLine())!=null)
{
System.out.println(line);
}
}
}
login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="/demo2/demo" method="post">//action属性:设置表单提交的服务器地址
<input type="text" placeholder="请输入用户名" name="username"><br>
<input type="text" placeholder="请输入密码" name="password"><br>
<input type="submit" value="注册"><br>
</form>
</body>
</html>
获取请求参数的通用方式
根据参数名获取参数值:
package request;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//获取get请求参数
//根据参数名称获取参数值
String username=request.getParameter("username");
System.out.println("get方式:");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//获取post请求参数
//根据参数名称获取参数值
/* String username=request.getParameter("username");
System.out.println("post方式:");
System.out.println(username);*/
//因为doPost方法里面的代码逻辑和doGet方法里面代码逻辑相同,因此可以在doPost方法里面直接调用doGet方法
//简化代码书写
doGet(request,response);
}
}
根据参数名称获取参数值数组,多用于复选框:
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String[] hobbies=request.getParameterValues("hobby");
for(String hobby:hobbies)
System.out.println(hobby);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request,response);
}
}
获取所有请求的参数名称
Enumeration<String> names= request.getParameterNames();
while(names.hasMoreElements())
{
String name=names.nextElement();
String value=request.getParameter(name);
System.out.println(name+":"+value);//对于复选框,如果有多个参数值,那么这里只能获取第一个参数值,除非用数组形式获取
}
获取所有参数的map集合
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> strings = parameterMap.keySet();
for(String value:strings)
{
//根据key获取值
String[] strings1 = parameterMap.get(value);
for(String s:strings1) {
System.out.println("key=" + value + " value=" + s);
}
}
上面的四种方法,第一种和第四种较为常用
请求中的中文乱码问题
- tomcat 8已经将get方式乱码解决,如果get方式还是有乱码,去配置中修改
- post方式中文会乱码
解决:
获取参数前,设置request的编码:
//1.设置流的编码
request.setCharacterEncoding("utf-8");
代码:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
//1.设置流的编码
request.setCharacterEncoding("utf-8");
Map<String, String[]> parameterMap = request.getParameterMap();
Set<String> strings = parameterMap.keySet();
for(String value:strings)
{
//根据key获取值
String[] strings1 = parameterMap.get(value);
for(String s:strings1) {
System.out.println("key=" + value + " value=" + s);
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request,response);
}
请求转发
一种在服务器内部资源跳转的方式
步骤
代码:
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
System.out.println("转发到dem0....");
//转发到reqServlet3下面的资源
/* RequestDispatcher requestDispatcher = request.getRequestDispatcher("/reqServlet3");
requestDispatcher.forward(request,response);*/
//一般多为链式编程
request.getRequestDispatcher("/reqServlet3").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request,response);
}
}
@WebServlet("/reqServlet3")
public class reqServlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("转发到reqServlet3....");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
共享数据(域对象)
域对象: 一个有作用范围的对象,可以在范围内共享数据
request 域: 代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
一般只有转发的情况下,才可以用request域共享数据
代码演示:
@WebServlet("/demo")
public class reqServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
System.out.println("转发到dem0....");
//存储数据到request域中
request.setAttribute("name","大忽悠");
request.getRequestDispatcher("/reqServlet3").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doGet(request,response);
}
}
@WebServlet("/reqServlet3")
public class reqServlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object name = request.getAttribute("name");
System.out.println((String)name);
System.out.println("转发到reqServlet3....");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
获取ServletContext对象
ServletContext servletContext = request.getServletContext();
用户登录案例
案例需求
案例分析
环境准备
- 创建项目,导入html页面,配置文件,导入jar包
- 创建数据库环境
USE test1;
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
3.创建一个user类
package domain;
public class user {
private int id;
private String username;
private String password;
public user(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public user() {
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setId(int id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
}
4.创建操作数据库中user表的类—UserDao
package Dao;
import Utils.JDBCUtils;
import domain.user;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class userDao {
//声明JDBCTemplate对象共用
private JdbcTemplate template=new JdbcTemplate(JDBCUtils.getDataSource());
//登录方法
public user login(user loginUser)
{
try
{
//编写sql语句
String sql="select * from user where username= ? and password= ?";
//调用query方法---返回一个查到的user对象
user user = template.queryForObject(sql, new BeanPropertyRowMapper<user>(user.class), loginUser.getUsername(), loginUser.getPassword());
//loginUser: 只包含用户名和密码
//返回的user: 包括用户全部数据
return user;
}
catch (DataAccessException e)
{
e.printStackTrace();
//没有查询到,返回null
return null;
}
}
}
一个例子教你看源码!深入浅出教你理解Template中的query和queryForObject的区别!
5.工具类
package Utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtils {
//定义成员变量---连接池对象
private static DataSource ds;
static {
try {
//加载配置文件
Properties pro=new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//初始化连接池对象
ds= DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接池对象
public static DataSource getDataSource()
{
return ds;
}
//获取连接Connection对象
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
- loginServlet类完成登录的具体逻辑
在这里插入代码片
7.login.html
login.html中的form表单的action路径写法
虚拟目录+ Servlet的资源路径
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form action="/demo5/LoginServlet" method="post">
用户名: <input type="text" name="username" placeholder="请输入用户名"><br>
密码: <input type="password" placeholder="请输入密码" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
8.配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///test1
username=root
password=root
#初始化连接数量
initialSize=5
#最大连接数
maxActive=10
#最大等待时间
maxWait=3000
最新版的IDEA需要把配置文件放置到如下两个地方:
否则报如下错误:
9.loginServlet–负责登录的相关逻辑
import Dao.userDao;
import domain.user;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置编码
request.setCharacterEncoding("utf-8");
//2.获取请求参数
String usermame= request.getParameter("username");
String password = request.getParameter("password");
//3.封装user对象
user loginUser=new user(usermame,password);
//4.调用userDao的login方法
userDao dao=new userDao();
user user=dao.login(loginUser);
//5.判断user
if(user==null)
//登录失败
request.getRequestDispatcher("/FailServlet").forward(request,response);
else
{
//登录成功
//存储数据
request.setAttribute("user",user);//将查到的user对象存入
//转发
request.getRequestDispatcher("/SuccessServlet").forward(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
10.FailServlet—处理登录失败的逻辑
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/FailServlet")
public class FailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//给页面写一句话
//设置页面的编码
response.setContentType("text/html;charset=utf-8");
System.out.println("登录失败");
//输出
response.getWriter().write("登录失败,用户名或者密码错误");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
11.SuccessServlet—处理登录成功的逻辑
import domain.user;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/SuccessServlet")
public class SuccessServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取request域中共享的user对象
user user= (user)request.getAttribute("user");
//给页面写一句话
//设置编码
response.setContentType("text/html;charset=utf-8");
System.out.println("登录成功");
//输出
response.getWriter().write("欢迎"+user.getUsername()+"用户");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
效果演示:
数据库目前只有一位用户登录成功:
登录失败的演示:
登录成功的演示:
BeanUtils工具类,简化数据封装
用于封装JavaBean的
JavaBean: 标准的Java类
- 类必须被public修饰
- 必须提供空参的构造器
- 成员变量必须使用private修饰
- 必须提供公共的setter和getter方法
- 一般像这种JavaBean的类都会放在domain等的包下面
功能:封装数据
概念
- 成员变量
- 属性: setter和getter截取后的产物,例如: getUsername()—>Username(下一步变小写)–>username,这里的username一般就是成员变量的名字
这里是通过通过传入的字符串和方法名截取后的产物进行比对,找到正确的方法,来设置属性值或者得到属性值
方法
- setProperty()—>给属性赋值
- getProperty()---->得到属性的值
- populate(Object obj,Map map):将map集合的键值对信息封装到对应的JavaBean对象中,把键作为属性的名称,值作为JavaBean对应属性的值
BeanUtils工具类使用前要导入jar包
setProperty()和getProperty()方法演示:
user loginUser=new user();
//设置loginUser的属性
BeanUtils.setProperty(loginUser,"username","大忽悠");
System.out.println(loginUser);
user loginUser=new user("大忽悠","123456");
String name= BeanUtils.getProperty(loginUser,"username");
System.out.println(name);
populate方法演示:
/*
//2.获取请求参数
String usermame= request.getParameter("username");
String password = request.getParameter("password");
//3.封装user对象
user loginUser=new user(usermame,password);
*/
//获取所有请求参数
Map<String, String[]> parameterMap = request.getParameterMap();
//创建user对象
user loginUser=new user();
//使用BeanUtils进行封装
try {
BeanUtils.populate(loginUser,parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
HTTP响应消息
服务器端发送给客户端的数据
数据格式:
1. 响应行
2. 响应头
3. 响应空行
4. 响应体: 传输的数据
Reponse对象
设置响应消息
1.设置响应行
- 格式: http/1.1 200 ok
- 设置状态码:
setStatus(int sc)
2.设置响应头
setHeader(String name,String value);
3.设置响应体
使用步骤:
-
获取输出流
-
使用输出流,将数据输出到客户端浏览器
案例之完成重定向
重定向: 资源跳转的方式
代码演示:
//访问Demo1资源,自动跳转到Demo2资源
//1.设置状态码为302
response.setStatus(302);
//2.设置响应头location
response.setHeader("location","/Demo2Servlet");
简单的重定向写法:
response.sendRedirect("/Demo2Servlet");
重定向和转发的区别和各自特点
路径写法
路径分类
不写默认代表./ ,即当前目录下
动态获取虚拟目录
String contextPath = request.getContextPath();//虚拟目录
response.sendRedirect(contextPath+"/Demo2Servlet");
服务器输出字符数据到浏览器
- 获取字符输出流
- 输出数据
代码演示:
//获取字符输出流
PrintWriter writer = response.getWriter();
//输出数据
writer.write("<font color=red size=5>Hello world</font>");
中文乱码问题
解决方法:
//获取流对象之前,设置流的默认编码: ISO-8859-1 设置为GBK
response.setCharacterEncoding("GBK");
//获取字符输出流
PrintWriter writer = response.getWriter();
//输出数据
writer.write("<font color=red size=5>大忽悠</font>");
如果在不知道浏览器编码格式的情况下,解决方法如下:
//获取流对象之前,设置流的默认编码: ISO-8859-1 设置为GBK
response.setCharacterEncoding("utf-8");
//告诉浏览器,服务器发送的消息体数据编码,建议浏览器使用该编码编码
response.setHeader("content-type","text/html;charset=utf-8");
//获取字符输出流
PrintWriter writer = response.getWriter();
//输出数据----这里可以使用html标签,浏览器可以解析
writer.write("<font color=red size=5>大忽悠</font>");
对上面一种方法的简化写法:
response.setContentType("text/html;charset=utf-8");
//获取字符输出流
PrintWriter writer = response.getWriter();
//输出数据
writer.write("<font color=red size=5>大忽悠来了</font>");
服务器输出字节数据到浏览器
- 获取字节输出流
- 输出数据
代码演示:
response.setContentType("text/html;charset=utf-8");
//获取字节输出流
ServletOutputStream outputStream = response.getOutputStream();
//输出数据
outputStream.write("大忽悠".getBytes(StandardCharsets.UTF_8));//如果这里不设置字符集,默认使用GBK
一般使用字节输出流来输出图片和视频,而非文本信息
字节输出流案例----验证码
验证码本质是个图片,目的是为了来防止恶意表单注册
完整代码演示:
Demo1Servlet:
package com.example.DEMO7;
import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Random;
@WebServlet("/Demo1Servlet")
public class Demo1Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width=150;
int height=50;
//1.在内存中创建一个图片----创建一个不带透明色的对象
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//2.填充背景色
Graphics g=image.getGraphics();//画笔对象
g.setColor(Color.PINK);
g.fillRect(0,0,width,height);
//3.画边框
g.setColor(Color.BLUE);
g.drawRect(0,0,width-1,height-1);
//4.随机生成验证码
String str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random ran=new Random();
for(int i=1;i<=4;i++)
{
//生成随机角标
int index=ran.nextInt(str.length());
//获取字符
char ch=str.charAt(index);
//写验证码
g.drawString(ch+" ",width/5*i,height/2);
}
//7.画干扰线
//随机生成坐标点
for(int i=0;i<4;i++)
{
int x1=ran.nextInt(width);
int x2=ran.nextInt(width);
int y1=ran.nextInt(height);
int y2=ran.nextInt(height);
g.setColor(Color.RED);
g.drawLine(x1,y1,x2,y2);
}
//8.将图片输出到页面上----第二个参数是后缀名,第三个参数是一个输出流
ImageIO.write(image,"jpg",response.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
register.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>战地六中国区官网</title>
<script>
/*
* 分析:
* 点击超链接或者图片,需要换一张验证码图片
* 1.给超链接和图片绑定单击事件
* 2.重新设置图片的src属性值
* */
//当页面加载完成,触发下面的事件
window.onload=function (){
//1.获取图片对象
var img=document.getElementById("checkCode");
//2.绑定单击事件
img.onclick=function ()
{
//浏览器会有缓存,因此需要加一个时间戳,保证每次的资源路径都不同
var date=new Date().getTime();
img.src="/Demo7/Demo1Servlet?"+date;
}
}
</script>
</head>
<body>
<form action="/Deom7/Demo1Servlet" method="get">
游戏激活码:<input type="text" placeholder="请输入激活码"><br>
验证码:<input type="text" placeholder="输入图片验证码">
<img id="checkCode" src="/Demo7/Demo1Servlet"/>
<a id="change" href="http://localhost/Demo7/register.html">看不清换一张?</a>
</form>
</body>
</html>
ServletContext对象
概念: 代表整个web应用,可以和程序的容器来通信
获取
代码演示:
//1.通过request对象获取
ServletContext servletContext = request.getServletContext();
//2.通过HttpServlet获取
ServletContext servletContext1 = this.getServletContext();
System.out.println(servletContext1);
System.out.println(servletContext);
System.out.println(servletContext1==servletContext);//true
功能
1.获取MIME类型
代码演示:
//通过HttpServlet获取
ServletContext servletContext = getServletContext();
//定义文件名称
String filename="a.jpg";
//获取MIME类型
String mimeType = servletContext.getMimeType(filename);
System.out.println(mimeType);
2.域对象,共享数据
ServletContext对象的生命周期从服务器被创建时开始,到服务器被关闭时结束,并且作用范围很广,为所有用户,因此要谨慎使用
3.获取文件服务器路径
服务器中不同目录下的文件获取时填写路径不同,需要注意
//获取ServletContext对象----HTTP方式
ServletContext servletContext = getServletContext();
//获取文件的服务器路径
//web目录下的资源访问
String realPath = servletContext.getRealPath("/b.txt");
System.out.println(realPath);
//web-inf目录下的资源访问
String realPath1 = servletContext.getRealPath("/WEB-INF/c.txt");
System.out.println(realPath1);
//java目录下的资源访问
String realPath2 = servletContext.getRealPath("/WEB-INF/classes/a.txt");
System.out.println(realPath2);
文件下载案例
文件下载需求:
- 页面显示超链接
- 点击超链接后弹出下载提示框
- 完成图片文件下载
分析:
步骤:
上面说过的响应头相关知识回顾:
代码实现:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数,即文件名称
String filename=request.getParameter("filename");
//使用字节输入流加载文件进内存
//第一步: 找到文件服务器路径
ServletContext servletContext = getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
//第二步: 用字节流关联
FileInputStream fis=new FileInputStream(realPath);
//设置response的响应头
//第一步: 设置响应头的类型: content-type
String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
response.setHeader("content-type",mimeType);
//第二步: 设置响应头打开的方式: content-disposition
response.setHeader("content-disposition","attachment;filename="+filename);//filename=....弹出提示框的名字
//将输入流数据写到输出流中
ServletOutputStream outputStream = response.getOutputStream();
byte[] buff=new byte[1024*8];
int len=0;
while((len=fis.read(buff))!=-1)
{
outputStream.write(buff,0,len);
}
//关闭输入流
fis.close();
}
downLoad.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<a href="/demo9/img/cat.png">可爱小猫</a>
<a href="/demo9/img/lion.png">猛狮</a>
<hr>
<font color="#ff69b4" size="5">下面链接,点击下载图片</font><br>
<a href="/demo9/downLoadServlet?filename=cat.png">小猫图片下载</a>
<a href="/demo9/downLoadServlet?filename=lion.png">狮子图片下载</a>
</body>
</html>
中文文件名问题
解决:
如果jdk版本打印1.8,那么需要手动导入BASE64Encoder的jar包,方可使用其工具类
工具类代码:
package com.example.Demo9;
import Decoder.BASE64Encoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class downLoadUtils {
public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}
之前出问题的servlet主类:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数,即文件名称
String filename=request.getParameter("filename");
//使用字节输入流加载文件进内存
//第一步: 找到文件服务器路径
ServletContext servletContext = getServletContext();
String realPath = servletContext.getRealPath("/img/" + filename);
//第二步: 用字节流关联
FileInputStream fis=new FileInputStream(realPath);
//设置response的响应头
//第一步: 设置响应头的类型: content-type
String mimeType = servletContext.getMimeType(filename);//获取文件的mime类型
response.setHeader("content-type",mimeType);
//第二步: 设置响应头打开的方式: content-disposition
///
//解决中文文件名问题
//1.获取user-agent请求头
String agent=request.getHeader("user-agent");
//2.使用工具类方法编码文件名即可
filename = downLoadUtils.getFileName(agent, filename);
///
response.setHeader("content-disposition","attachment;filename="+filename);//filename=....弹出提示框的名字
//将输入流数据写到输出流中
ServletOutputStream outputStream = response.getOutputStream();
byte[] buff=new byte[1024*8];
int len=0;
while((len=fis.read(buff))!=-1)
{
outputStream.write(buff,0,len);
}
//关闭输入流
fis.close();
}