今日内容
零、复习昨日
一、接收请求
二、处理响应
三、综合案例
零、复习昨日
画图, 请求处理的完整流程(javaweb开发流程)
零、注解改造
@WebServlet注解,相当于是在web.xml中配置的servlet映射
Servlet类
package com.qf.servlet;
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;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc
* 注解@WebServlet取代web.xml中的配置
* 服务器运行时会处理这个注解
* 根据注解后的参数匹配请求路径
*/
@WebServlet("/a")
public class MyServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("接收请求" );
}
}
web.xml , 内容不用配置
<?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_3_1.xsd"
version="3.1">
<!-- @WebServlet("/a")可以取代以下配置-->
<!-- <servlet>-->
<!-- <servlet-name>aServlet</servlet-name>-->
<!-- <servlet-class>com.qf.servlet.MyServlet1</servlet-class>-->
<!-- </servlet>-->
<!-- <servlet-mapping>-->
<!-- <servlet-name>aServlet</servlet-name>-->
<!-- <url-pattern>/a</url-pattern>-->
<!-- </servlet-mapping>-->
</web-app>
启动项目,访问/a路径即可
一、接收请求
需求: html页面中写一个表单,发送请求,后台服务器接收所有请求数据
1.1 编写页面
index.jsp或者index.html都行
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<%--
input必须加name属性,因为后台服务器通过name获取输入框的值
单选,复选框,选择框,需要设置value属性,后台服务器获得是value的值
文件上传比较特殊,后续单独讲,暂时忽略
--%>
<h1>演示:servlet接收请求数据</h1>
<form action="/req" method="get">
<table>
<tr>
<td>
用户名
</td>
<td>
<input type="text" name="username">
</td>
</tr>
<tr>
<td>
密码
</td>
<td>
<input type="password" name="password">
</td>
</tr>
<tr>
<td>
性别
</td>
<td>
<input type="radio" name="sex" value="1">男
<input type="radio" name="sex" value="2">女
</td>
</tr>
<tr>
<td>
爱好
</td>
<td>
<input type="checkbox" name="hobby" value="1">唱歌
<input type="checkbox" name="hobby" value="2">跳舞
<input type="checkbox" name="hobby" value="3">rap
</td>
</tr>
<tr>
<td>
生日
</td>
<td>
<input type="date" name="birthday">
</td>
</tr>
<tr>
<td>
学历
</td>
<td>
<select name="xl">
<option value="1">大专</option>
<option value="2">本科</option>
<option value="3">研究生</option>
</select>
</td>
</tr>
<tr>
<td>
提交
</td>
<td>
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
</body>
</html>
1.2 编写Servlet
package com.qf.servlet;
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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 演示接收请求数据
*/
@WebServlet("/req")
public class MyServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 请求中有请求方法,请求路径以及请求数据
* ----------------------------------
* 通过doGet方法参数1 HttpServletRequest req对象来获得请求数据
* ps:当请求到达该类的这个方法时,该参数req就会被赋值,其中就有关于请求的所有东西
*/
String method = req.getMethod( );
String uri = req.getRequestURI( );
StringBuffer url = req.getRequestURL( );
System.out.println("method = " + method);
System.out.println("uri = " + uri);// uri资源标识符
System.out.println("url = " + url);// url资源定位符
// ===============获得请求数据[重点]===================
/**
* 获得请求参数的方法是
* req.getParameter("key"); key就是前端标签name值
* [重点:] 后端获得的数据全都是字符串,如果需要后续使用,
* 还需按照性质做相应的转换
* 比如: 字符串转数字,字符串转日期
*/
String username = req.getParameter("username");
String password = req.getParameter("password");
String sex = req.getParameter("sex");
// int i = Integer.parseInt(sex);
String birthday = req.getParameter("birthday");
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// try {
// Date parse = sdf.parse(birthday);
// } catch (ParseException e) {
// e.printStackTrace( );
// }
String xl = req.getParameter("xl");
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println("sex = " + sex);
System.out.println("birthday = " + birthday);
System.out.println("xl = " + xl);
// 多选框使用getParameterValues()
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println("hobby = " + hobby );
}
}
}
总结:
- req.getParameter(“”) 能获得请求数据
- req.getParameterValues(“”) 能获得请求数据
1.3 配置web.xml
注解开发,不需要配置
1.4 部署项目
1.5 启动测试
复习回顾
前端
html,css,js/jq后端服务器:
1开发架构有哪些:
- b/s,
- c/s
2服务器是干什么的?
- 运行web项目项目容器
- 接收请求,做出响应
3浏览器如何发出的请求
- 常见的如,a标签,form表单
- js中使用ajax发请求
- vue中使用axios发请求
4发请求后如何与后端servlet类关联的?
(或者说绑定的?一一映射的?)
- 没注解时,通过web.xml文件一一映射关联
- 有注解,通过注解@WebServlet(“/路径”)中设置路径
5什么时候servlet类会执行doGet方法,什么时候执行doPost方法?
- 前端发get,后端就执行doGet
- 前端发post,后端就执行doPost
6写出完整的项目(假设项目命名his)http请求路径,以登录(login)请求为例
- 协议://ip:端口/资源?k=v&k=v
- jdbc:mysql://localhost:3306/java2313?useSSL=false&serverTimeZone=utc
- http://localhost:8080/his/login?username=admin&password=123456
7画图, 请求处理的完整流程(javaweb开发流程)
8具体如何接收请求中的数据?
- 通过HttpServletRequest对象接收请求中的数据
- 通过req对象调用getParameter(“key”)
二、做出响应
做出响应是通过HttpServletResponse对象
- 响应正文
- 向浏览器展现的内容
package com.qf.servlet;
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;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 演示接收请求数据,响应内容
*/
@WebServlet("/req")
public class MyServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// ....
// ==================演示响应=======================
/**
* 响应是通过HttpServletResponse resp对象来完成
* 响应可以设置响应内容(即展示在浏览器上的内容)
* -----------------------------------------
* ps: 其实响应也可以设置响应状态码,但是一般不需要,服务器会自动设置状态码
* 但是需要知道一些常见状态码:
* 200 成功, 404 资源未找到, 500 服务器内部错误,
* 405 get/post请求方式不对,400 一般是数据解析出错了
*/
// 响应乱码,在响应前设置编码格式
resp.setContentType("text/html;charset=utf-8");
// 响应是通过输出流的形式实现
PrintWriter out = resp.getWriter( );
//out.write("hello this is response - 这是响应");
out.write("<html>");
out.write("<head><title>响应</title></head>");
out.write("<body>");
out.write("<h1>这是响应的页面</h1>");
out.write("<div style='color:red'>div</div>");
out.write("<p style='color:red'>"+username+"</p>");
out.write("</body>");
out.write("</html>");
}
}
三、乱码解决
请求乱码
req.setCharacterEncoding("utf-8");
响应乱码
resp.setContentType("text/html;charset=utf-8");
四、 综合案例-登录(Servlet + JDBC)
- 要求:实现登录功能
第一步: 先设计数据库
库,表 (ORM,要根据表设置实体类)
登录页面
html/jsp
表单发送请求,携带数据
后台服务器代码
servlet,接收数据
jdbc+orm
servlet,做出响应
4.0 项目结构[重点]
web开发有三层架构
- 控制层 -servlet 流程控制,是指整个请求响应的流程
- 业务层 - service - 是指在请求接收后,对数据按照需求处理
- 数据访问层 - DataAccessObject - DAO
4.1 数据库
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
`sex` char(1) DEFAULT NULL,
`money` double(10,2) DEFAULT NULL,
`createTime` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
实体类 - ORM
需要创建一个包,专门存储实体类,一般命名pojo/entity/model
public class User {
// 列名对属性名
private int id;
private String username;
private String password;
private String sex;
private double money;
private Date createTime;
// set get 构造 toString
}
4.2 pom依赖
<!-- 引入servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 引入jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<!-- DbUtils依赖 -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
</dependency>
4.3 登录页面
index.jsp
<body>
<h2>登录</h2>
<form action="/login" method="post">
用户名<input type="text" name="username"><br>
密码<input type="password" name="password"><br>
<input type="submit" value="提交"><br>
</form>
</body>
4.4 控制层Servlet
Servlet只负责接收请求数据,做出响应
如果要处理数据,那就调用业务层
package com.qf.servlet;
import com.qf.model.Admin;
import com.qf.service.AdminService;
import com.qf.service.AdminServiceImpl;
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;
import java.util.List;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 命名
* 功能+层
* LoginServlet
* LoginService
* LoginDao
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 防止乱码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 1 接收请求数据
String username = req.getParameter("username");
String password = req.getParameter("password");
// servlet调用service(业务层)
LoginService service = new LoginService( );
User user = service.login(username, password);
// 做出响应
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter( );
if (user != null) { // 登录成功
writer.write("登录成功!");
writer.write(user.toString());
} else { // 登录失败
writer.write("登录失败!用户名或密码错误");
}
}
}
4.5 业务层service
业务层就处理项目业务逻辑的,业务逻辑包含哪些内容?
- 除了servlet接收请求做出响应以及jdbc操作数据库的代码,其他全是业务逻辑
- 加密解密
- 处理上传下载excel表格
- 处理项目中数据格式
- 计算项目中涉及金额
- 缓存处理
- 购物车,订单,支付
- 短信,验证码,定时调度,推送
- …等等
业务层代码编码
- 需要创建包结构service
LoginService
public class LoginService {
/**
* 业务层要定义方法,能接收数据,处理后返回数据
* -----
* 登录一般返回的是实体类
* - 登录成功,返回实体类对象中有数据
* - 登录失败,返回实体类对象是null
* ----------------------
* 业务层需要调用数据层 操作数据库
*/
public User login(String username, String password){
// 处理业务
// ...
// 处理后,要将数据继续传递给dao层
LoginDao loginDao = new LoginDao( );
User user = loginDao.login(username, password);
return user;
}
}
4.6 数据访问层dao
数据访问层 Data Access Object - DAO
项目需要创建dao层代码专门操作数据库
dao层编码
LoginDao
public class LoginDao {
public User login(String username,String password) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/java23132?useSSL=false", "root", "123456");
ps = conn.prepareStatement("select * from tb_user where username = ? and password = ?");
ps.setString(1,username);
ps.setString(2,password);
rs = ps.executeQuery( );
while (rs.next()) {
User user = new User( );
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setSex(rs.getString("sex"));
user.setMoney(rs.getDouble("money"));
user.setCreateTime(rs.getDate("createTime"));
return user;
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
rs.close();
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace( );
}
}
return null;
}
}
4.7 测试
登录页面
登录成功
登录失败
4.8 总结
重点
- 熟悉开发的流程
- 熟记开发架构 (控制层,业务层,数据访问层)
- 响应拼接页面方式,了解即可
- 前后端发请求,做响应
经验总结
1 写项目不要照抄,应该按照流程一步一步写
(前端–>servlet–>service–>dao–>service—>servlet–>前端)
2 学会看异常
- 前端页面报错404,405,500
- 后端控制台要查看异常(注意几个关键词,Exception,error,caused by ,at …)
3 逻辑bug
- 前端页面没有报错,后端控制台有没有报错,但是结果不对
- 这就是bug,该怎么解决?
从头(按照流程)读,检查代码,去输出
,高端玩家打断点
4 如果确定前端,后端,数据库都没问题,考虑缓存
- idea缓存(file-invalidate cache)(删除target文件夹)
- 浏览器缓存(清空)
5 学会倒推
五、注册功能
(如何写需求?建议当做用户,见到什么写什么,需要什么写什么)
注册 —> 向数据库插入数据
5.1 跳转注册
5.2 注册页面
5.3 发请求,后端Servlet接收
注意接收的中文防止乱码
5.4 UserService
注意: 将之前的LoginService重命名为UserService,因为一个类中可以定义多个方法,不需要创建很多类
5.5 UserDao
注意日期bug,只能是java.sql.Date类型
5.6 UserDao返回给UserService
5.7 UserService在返回给RegistServlet
5.8 Servlet根据结果做响应
六、作业-查询全部
登录成功后查询全部,并展示全部