目录
三、表述层 (Servlet),修改html表单地址,封装bean对象
一、请求 Request
Request就是服务器中的一个对象,该对象中封装了HTTP请求的请求行、请求头和请求体的内容。
Request获取HTTP请求的内容:
1.请求行、请求头
public class ServletRequest1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求行信息
//获取请求方式
String method = request.getMethod();
System.out.println("method = " + method);
//获取URL 统一资源定位符
StringBuffer requestURL = request.getRequestURL();
System.out.println("requestURL = " + requestURL);
//获取URI 统一资源标识符
String requestURI = request.getRequestURI();
System.out.println("requestURI = " + requestURI);
//获取协议
String protocol = request.getProtocol();
System.out.println("protocol = " + protocol);
//获取请求头信息
//获取客户端信息
String agent = request.getHeader("User-Agent");
System.out.println("agent = " + agent);
//获取引用页(上一页) 防止盗链
String referer = request.getHeader("Referer");
System.out.println("referer = " + referer);
}
}
<body>
<form action="request1">
<h1>获取请求行、头信息</h1>
<input type="submit"> <br>
</form>
</body>
Request 获取请求参数(重要)
方法名 | 返回值类型 | 方法描述 |
---|---|---|
request.getParameter("请求参数的名字") | String | 根据一个参数名获取一个参数值 |
request.getParameterValues("请求参数的名字") | String [] | 根据一个参数名获取多个参数值 |
request.getParameterNames() | Enumeration<String> | 获取当前请求的所有参数的参数名 |
request.getParameterMap() | Map<String, String[]> | 获取当前请求的所有参数,以键值对的方式存储到Map中 |
request.setCharacterEncoding("utf-8"); | Post会中文乱码,需要设置编码解决 |
public class ServletRequest2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.根据一个参数名获取一个参数值
System.out.println("---------- getParameter() ----------");
String uname = request.getParameter("uname");
String pwd = request.getParameter("pwd");
System.out.println(uname + "->" +pwd);
//2.根据一个参数名获取多个参数值
System.out.println("---------- getParameterValues() ----------");
String[] hobbies = request.getParameterValues("hobby");
System.out.println("hobby->"+ Arrays.toString(hobbies));
//3.获取当前请求的所有参数,以键值对的方式存储到Map中
System.out.println("---------- parameterMap() ----------");
Map<String, String[]> parameterMap = request.getParameterMap();
parameterMap.forEach(new BiConsumer<String, String[]>() {
@Override
public void accept(String s, String[] strings) {
System.out.println(s+"->"+Arrays.toString(strings));
}
});
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Post会中文乱码,需要设置编码解决(因为系统默认utf编码)
request.setCharacterEncoding("utf-8");
//1.根据一个参数名获取一个参数值
System.out.println("---------- getParameter() ----------");
String uname = request.getParameter("uname");
String pwd = request.getParameter("pwd");
System.out.println(uname + "->" +pwd);
}
}
<body>
<h1>get的方式</h1>
<form action="request2">
用户名: <input type="text" name="uname"> <br>
密码: <input type="password" name="pwd"> <br>
爱好:<input type="checkbox" name="hobby" value="swim"> 游泳
<input type="checkbox" name="hobby" value="read"> 读书
<input type="checkbox" name="hobby" value="run"> 跑步 <br>
<input type="submit"> <br>
</form>
<h1>post的方式</h1>
<form action="request2" method="post">
用户名: <input type="text" name="uname"> <br>
密码: <input type="password" name="pwd"> <br>
爱好:<input type="checkbox" name="hobby" value="swim"> 游泳
<input type="checkbox" name="hobby" value="read"> 读书
<input type="checkbox" name="hobby" value="run"> 跑步 <br>
<input type="submit"> <br>
</form>
</body>
BeanUtils工具类
Apache 下的软件包,其主要目的是利用反射机制对 JavaBean 的属性进行处理。(此处只是用来将表单数据快速封装为对象)
//调用getParameterMap() 获取当前请求内表单中的所有参数,
Map<String, String[]> userMap = request.getParameterMap();
//准备一个User对象
User user = new User();
//进行封装,完成
BeanUtils.populate(user,userMap);
不使用工具封装对象:
//获取所有参数
Map<String, String[]> userMap = request.getParameterMap();
String uname = userMap.get("uname")[0]; //获取name
String age = userMap.get("age")[0]; //获取age
String gender = userMap.get("gender")[0]; //获取gender
User user = new User(uname,age,gender);
Request 请求转发(服务器内部转发)
请求转发:从一个资源跳转到另一个资源,浏览器只会发起一次请求,连接不会发生改变 。
请求转发可以跳转到WEB-INF中的资源。
请求转发的API:
request.getRequestDispatcher("路径").forward(request,response);
代码:
public class ServletDispatcher1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------ Dispatcher1 duGet() ------");
String uname = request.getParameter("uname");
System.out.println("uname = " + uname);
//将请求传递到 Dispatcher2
request.getRequestDispatcher("/dispatcher2").forward(request,response);
}
}
public class ServletDispatcher2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------ Dispatcher2 duGet() ------");
//同一个链接,可以获取当前链接资源
String uname = request.getParameter("uname");
System.out.println("Dispatcher2 uname = " + uname);
//请求转发访问WEB-INF内的资源
request.getRequestDispatcher("/WEB-INF/dispatcher.html").forward(request,response);
}
}
regist.html
<h1>请求转发</h1>
<form action="dispatcher1">
用户名: <input type="text" name="uname"> <br>
<input type="submit">
</form>
web.xml
<servlet-mapping>
<servlet-name>ServletDispatcher1</servlet-name>
<url-pattern>/dispatcher1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ServletDispatcher2</servlet-name>
<url-pattern>/dispatcher2</url-pattern>
</servlet-mapping>
WEB-INF内资源
<body> <h1>成功访问WEB—INF资源</h1> </body>
请求域对象
全局域是整个项目范围的所有动态资源都能够共享的一个范围;而请求域的范围只是在一次请求中的动态资源能够共享的一个范围。
往请求域中存入数据:
request.setAttribute(key,value)
从请求域中取出数据:
request.getAttribute(key)
(全局域对象是通过ServletContext.serAttribute设置)
请求域对象一定要和请求转发一起使用,因为请求域的范围是一次请求范围内,所以要在两个动态资源中使用请求域必须要进行请求转发跳转。
二、响应 Response
Response也是服务器端一个对象,它里面可以封装要响应给客户端的响应行、头、体的信息。
向客户端反馈信息、解决乱码问题:
setContentType("text/html;charset=utf-8");
该方法同时让服务器和客户端都使用UTF-8,还设置了响应头。
一定要在获取流对象之前调用。
public class ServletResponse1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//向用户反馈数据,解决响应乱码问题
response.setContentType("text/html;charset=utf-8");
//反馈信息
response.getWriter().println("ServletResponse1成功!");
}
}
请求和响应:
向客户端响应一个文件 (getOutputStream)
ServletOutputStream os = response.getOutputStream();
public class ServletResponse2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.先通过Context获取文件真实路径
ServletContext s1 = getServletContext();
String realPath = s1.getRealPath("img/200F6093053-7.jpg");
//2.创建输入流,读取图片
FileInputStream fis = new FileInputStream(realPath);
//3.通过Response获取输出流
ServletOutputStream os = response.getOutputStream();
//4.边读边写
int length =0;
while ((length=fis.read())!=-1){
os.write(length);
}
//5.关闭流
//可以使用codota插件 或 IOUtils工具 快捷完成
//IOUtils.copy(fis,os);
}
}
重新定向 (sendRedirect)
重定向是由项目中的一个资源跳转到另一个资源,在这个过程中客户端会发起新的请求。
重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求
重定向跳转可以跳转到任意服务器的资源,但是无法访问WEB-INF中的资源
重定向跳转浏览器的地址栏中的地址会变成跳转到的路径
重定向的API:
response.sendRedirect("路径");
代码:
public class ServletResponse3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取上下文路径
String contextPath = request.getContextPath();
//重定向 此时/代表服务器根目录,响应状态码302
response.sendRedirect(contextPath+"/response2");
}
}
请求转发和重定向的区别:
重定向会由浏览器发起新的请求,而请求转发不会发起新的请求。
重定向可以访问任意互联网资源,而请求转发只能访问本项目资源。
重定向不能访问本项目的WEB-INF内的资源,而请求转发可以访问本项目的WEB-INF内的资源。
发起重定向的资源和跳转到的目标资源没在同一次请求中,所以重定向不能在请求域中使用;而发起请求转发的资源和跳转到的目标资源在同一次请求中,所以请求转发可以在请求域中使用。
三、项目:书城二阶段: 登录注册功能_数据库链接
注意:jar包,lib文件夹放在 WEB-INF下!
一、使用base标签统一页面基础访问路径
base标签要写在head标签内,写在所有其他有路径的标签的前面。
base标签生效的机制是:最终的访问地址=base标签href属性设置的基准+具体标签内的路径
如果某个路径想要基于base中的路径进行路径编写,那么它不能以
/
开头
部分举例:
<html>
<head>
<!--base标签 当前页面下只要有资源引用的位置 都会先拼接base中的地址-->
<!--想要使用base 标签 引用资源位置前面 不能 有 /-->
<base href="/BookStore/">
<meta charset="UTF-8" />
<title>新日暮里会员登录页面</title> <!--由../../static..改为-->
<link type="text/css" rel="stylesheet" href="static/css/style.css" />
<script src="static/script/vue.js"></script>
</head>
Ctrl + R快速替换
二、编写实体类、数据库中创建表单
注意:html标签name值 需要与 实体类属性相同。
public class User {
//pojo 和 bean 都表示实体类
private Integer uid;
private String uname;
private String upwd;
private String email;
...略
}
CREATE TABLE t_user(
uid INT PRIMARY KEY auto_increment,
uname VARCHAR(50),
upwd VARCHAR(20),
email VARCHAR(20)
);
三、表述层 (Servlet),修改html表单地址,封装bean对象
注意:此时的业务层对象是在最后一步完成编写。
注册:
注册:
public class Regist extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------ Regist ------");
//1.解决请求,响应乱码问题
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=UTF-8");
//2.获取表单参数,封装为对象
Map<String, String[]> Map = request.getParameterMap();
try {
//3.工具类封装为对象 BeanUtils.populate(user(对象),userMap(参数集合));
User user = new User();
BeanUtils.populate(user, Map);
//4.调用业务层 判断是否可以添加
UserService userService = new UserServiceImpl();
//添加数据,没有发生异常注册成功
userService.registUser(user);
response.sendRedirect(request.getContextPath()+"/pages/user/regist_success.html");
} catch (Exception e) {
e.printStackTrace();
//4.2 发生异常则注册失败
response.getWriter().println("用户名已存在,注册失败。");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
登录:
登录:
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------ Login ------");
//1.解决请求,响应乱码问题
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=UTF-8");
//2.获取表单参数
Map<String, String[]> map = request.getParameterMap();
try {
//3.调用工具类封装为对象
User user = new User();
BeanUtils.populate(user,map);
//4.创建业务层对象,完成登录
UserServiceImpl userService = new UserServiceImpl();
User login = userService.login(user);
//登陆成功
response.sendRedirect(request.getContextPath()+"/pages/user/login_success.html");
} catch (Exception e) {
//登陆失败
e.printStackTrace();
response.getWriter().println("登录失败,请检查您的用户名或密码");
}
}
}
四、数据访问层(DAO) (暂时使用JDBC)
代码:和下面差不多
Day50.JDBC — 数据库连接池、DBUtils工具类、封装DOA层代码、ThreadLocal_焰火青年·的博客-CSDN博客
五、业务层 (Service)、密码MD5处理
//用户业务层
public interface UserService {
//注册业务
void registUser(User user);
//登录业务
User login(User user);
}
注册:
//业务层实现类
public class UserServiceImpl implements UserService {
//创建用户数据访问层对象
UserDaoImpl userDao = new UserDaoImpl();
//注册的方法
@Override
public void registUser(User user) {
//1.获取用户名
String uname = user.getUname();
//2.判断用户名是否已经存在
User user1 = userDao.selectByName(uname);
if(user1==null){
//3.1 不存在,对密码加密操作,存入数据
String encode = MD5Util.encode(user.getUpwd());
user.setUpwd(encode);
//通过数据访问层添加到数据库
userDao.insertUser(user);
} else {
//3.2 如果存在,无法存储
throw new RuntimeException("用户"+uname+"已存在,无法添加");
}
}
登录:
//登录的方法
@Override
public User login(User user) {
//1.根据用户名查询是否存在此用户
User u = userDao.selectByName(user.getUname());
//2.判断用户名是否存在
if(u!=null){
//3.密码是否一致(先将密码转为MD5)
String encode = MD5Util.encode(user.getUpwd());
if(encode.equals(u.getUpwd())){
//4.1 密码相同返回 User
return u;
}else {
//4.2 密码不同抛出异常
throw new RuntimeException("密码错误");
}
} else {
//2,2用户名不存在,抛出异常
throw new RuntimeException("用户名不存在");
}
}
}
最后补充表述层代码,测试,完成。
六、补充:相关工具类
MD5Util
public class MD5Util {
/**
* 针对明文字符串执行MD5加密
* @param source
* @return
*/
public static String encode(String source) {
// 1.判断明文字符串是否有效
if (source == null || "".equals(source)) {
throw new RuntimeException("用于加密的明文不可为空");
}
// 2.声明算法名称
String algorithm = "md5";
// 3.获取MessageDigest对象
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 4.获取明文字符串对应的字节数组
byte[] input = source.getBytes();
// 5.执行加密
byte[] output = messageDigest.digest(input);
// 6.创建BigInteger对象
int signum = 1;
BigInteger bigInteger = new BigInteger(signum, output);
// 7.按照16进制将bigInteger的值转换为字符串
int radix = 16;
String encoded = bigInteger.toString(radix).toUpperCase();
return encoded;
}
}
JDBCUtils (Druid数据库连接池)
public class JDBCUtils {
static DataSource dataSource;
//ThreadLocal,每个线程独有,用于存储共享变量
static ThreadLocal<Connection> local = new ThreadLocal<>();
//静态代码块
static {
//属性集对象
Properties pro = new Properties();
try {
//将配置文件信息 读取到属性集内 (将配置文件信息转为 字节流)
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
//通过配置文件创建了链接对象
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
//通过连接池获取链接
public static Connection getConnection() throws SQLException {
Connection connection = local.get();
//如果ThreadLocalMap内不存在,用连接池获取,存在则直接返回
if(connection==null){
//连接池获取
connection = dataSource.getConnection();
//放入ThreadLocal内
local.set(connection);
}
return connection;
}
//关闭链接方法
public static void closeConnectiopn() throws Exception{
Connection connection = JDBCUtils.getConnection();
//事务关闭,防止后面复用出现问题
connection.setAutoCommit(true);
//删除线程内存储的链接
local.remove();
connection.close();
}
}
BaseDao (通用CURD)
public class BaseDaoImpl {
//通用的BaseDao 通用的增 删 改 查方法
public void update(String sql,Object...params) {
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
//3.执行操作
queryRunner.update(connection,sql,params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 通用的查询多条数据
* @param clazz 集合的泛型类型
* @param sql
* @param params 参数
* @param <T>
* @return
*/
//不确定查询哪张表,加入泛型!!!!
public <T> List<T> findAll(Class<T> clazz, String sql, Object... params) {
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
List<T> query = queryRunner.query(connection, sql, new BeanListHandler<>(clazz), params);
return query;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 通用的返回单个对象
* @param clazz bean的链接类型
* @param sql
* @param params 参数
* @param <T>
* @return
*/
public <T> T findOneBean(Class<T> clazz, String sql, Object... params) {
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
T bean = queryRunner.query(connection, sql, new BeanHandler<>(clazz), params);
return bean;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 通用的查询单个值,暂未用到
* @param sql
* @param params
* @return
*/
public Object getSingleValue(String sql,Object...params){
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
Object query = queryRunner.query(connection, sql, new ScalarHandler<>(), params);
return query;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}