JavaWeb(一)
一、创建Javaweb项目
配置好jdk,tomcat环境,我的是jdk8,tomcat9
ideal 创建一个普通Java工程
右键项目,添加Web App扩展
右上角添加你的配置,就是和你的tomcat联系在一起
左边选择本地的local Tomcat,在configrue选择你本地安装的tomcat路径
点击deployment 、点击加号添加扩展,下面那一行就是你浏览器访问的路径,然后点击Apply
点击sever,配置热部署,你默认的浏览器以及浏览网页
启动web项目,浏览器显示默认页面
二、前端数据提交到Java方法里面
web.xml配置前端数据提交到的某个Java类、即是一个继承于HttpServlet,重写了doGet和doPost方法的类
这是通过路径访问Servlet类,/test/hello需要加上你的网页路径
<?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-name>ServletTset</servlet-name>
<servlet-class>com.wang.study.bean.ServeltTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletTset</servlet-name>
<url-pattern>/test/hello</url-pattern>
</servlet-mapping>
</web-app>
注解写法,Servlet类上面加上@WebServlet注解
@WebServlet(name = "ServletTset",urlPatterns = "/test/hello")
前端页面from表单提交数据,action是提交地址,method是提交方法
<form action="/test/hello" method="post">
<input name="username" type="text"/>用户名
<input name="password" type="password"/>密码
<button type="submit">提交</button>
</form>
Servlet类,通过action提交地址就能找到某个类,method方法名找到doGet或者doPost方法
public class ServletTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端传入的数据
System.out.println("post");
String name = req.getParameter("username");
String pwd = req.getParameter("password");
System.out.println(name+pwd);
resp.sendRedirect("/views/main.html");
}
}
与Mybatis联合
1、三层架构
2、pom依赖
<dependencies>
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!--mysql连接jar包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
<!--servlet注解依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--junit单元测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<!-- 设置资源目录,使其可以读取dao下xml文件-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
3、dao层、实体类
接口
public interface StudentDao {
int addStudent(StudentEntity studentEntity);
}
xml
<mapper namespace="com.wang.study.dao.StudentDao">
<insert id="addStudent" parameterType="com.wang.study.entity.StudentEntity">
insert into student (id,s_name,age) value (#{sId},#{sName},#{age})
</insert>
</mapper>
实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentEntity {
private int sId;
private String sName;
private int age;
}
4、mybatis 全局配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncode=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentDao.xml"></mapper>
</mappers>
</configuration>
5、Mybatis辅助类,主要获取sqlsession
public class MybatisUtli {
private static SqlSessionFactory sqlSessionFactory;
static{
try{
String resourse = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resourse);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch(IOException e){
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
//System.out.println(sqlSessionFactory);
return sqlSessionFactory.openSession();
}
}
6、service层
接口
public interface StudentService {
int addStudent(StudentEntity studentEntity);
}
接口实现类
public class StudentServiceImpl implements StudentService {
SqlSession sqlSession = MybatisUtli.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
@Override
public int addStudent(StudentEntity studentEntity) {
int result = studentDao.addStudent(studentEntity);
sqlSession.commit();
sqlSession.close();
return result;
}
}
7、controller层
@WebServlet(name = "StudentServlet",urlPatterns = "/addStudent")
public class StudentServlet extends HttpServlet {
private StudentService studentService = new StudentServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*设置乱码*/
req.setCharacterEncoding("utf-8");
int id = Integer.parseInt(req.getParameter("id"));
String name = req.getParameter("name");
int age = Integer.parseInt(req.getParameter("age"));
StudentEntity studentEntity = new StudentEntity(id,name,age);
System.out.println(studentEntity.toString());
int result = studentService.addStudent(studentEntity);
if(result > 0){
resp.sendRedirect("/views/sucessful.html");
}else{
resp.sendRedirect("/views/fail.html");
}
}
}
8、前端数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/addStudent" method="get">
<input name="id" type="text"/>学号
<input name="name" type="text"/>用户名
<input name="age" type="text"/>年龄
<button type="submit">提交</button>
</form>
</body>
</html>
9、报错
如果找不到mysql驱动以及资源文件找不到,在output下添加依赖即可
四、请求处理
1、最原始的方法,response写,lowb的写法
PrintWriter writer = resp.getWriter();
writer.println("<html><head><body><h1>DSB123qqwe</h1></body></head></html>");
2、将后台数据传入到一个request中,由于html是静态页面,所以当前就使用jsp,jsp本质就是一个servlet,只不过jsp页面中能编写html以及jsp脚本能写Java
dao、service层新增一个查询所有学生的方法
controller层
@WebServlet(name = "StudentServlet",urlPatterns = "/students")
public class StudentServlet extends HttpServlet {
private StudentService studentService = new StudentServiceImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*servlet只有一个,mvc中要使用这个servlet进行请求转发*/
/*即在这个请求中加入method键值对,根据不同的值,进行转发*/
String method = req.getParameter("method");
if(method == null || "".equals(method)){
getAllStu(req,resp);
}
else if("getStudent".equals(method)){
}
}
/*查询所有学生*/
private void getAllStu(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<StudentEntity> list = studentService.getAllStu();
/*将数据封装在请求里面*/
req.setAttribute("students",list);
/*进行页面跳转,然后该页面取出数据*/
/*这是一个请求转发,url的路径不能发生变化*/
req.getRequestDispatcher("/views/students.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
前端jsp
<%--
Created by IntelliJ IDEA.
User: wyh
Date: 2021/9/24
Time: 10:44
To change this template use File | Settings | File Templates.
--%>、
<%--jsp指令语法导入包--%>
<%@ page import="com.wang.study.entity.StudentEntity" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
table{
border: 1px;
width: 100%;
border-collapse: collapse;
}
</style>
</head>
<body>
<%--jsp脚本语法,里面可以编写java程序--%>
<%
List<StudentEntity> list = (List<StudentEntity>)request.getAttribute("students");
%>
<table>
<tr>
<td>学号</td>
<td>姓名</td>
<td>年纪</td>
<td>操作</td>
</tr>
<%--for循环取出数据,这里要将td包裹在循环中--%>
<% for (int i = 0; i < list.size(); i++) {
StudentEntity u = list.get(i);
%>
<%-- <%=变量名 %> jsp通过变量名取值 --%>
<tr >
<td ><%=u.getSId()%></td >
<td ><%=u.getSName()%></td >
<td ><%=u.getAge()%></td >
<td ><a href="/TestMavenWeb/user3?method=getUser&id=<%=u.getSId()%>">修改</a></td >
</tr >
<% }%>
</table>
</body>
</html>
3、重定向返回一个新页面,url会发生变化
resp.sendRedirect("/views/main.html")
jsp JSTL标签库和模板引擎
由于jsp不需要过多的Java代码,并且jsp页面主要就是显示数据,
所以servlet
req.setAttribute("students",list);
jsp页面通过${名字}就能取出数据
<h1>${students}</h1>
pom添加依赖,jsp页面加入模板
<!--JSTL标签库-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
jsp加入模板
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
循环取出数据
<body>
<table>
<tr>
<td>学号</td>
<td>姓名</td>
<td>年龄</td>
</tr>
<c:forEach items="${studnets}" var="student">
<c:choose>
<c:when test="${student.id % 2 == 0}">
<tr style="background-color:#ccc;">
</c:when>
<c:otherwise>
<tr>
</c:otherwise>
</c:choose>
<td>${student.id}</td>
<td>${student.name}</td>
<td>${student.age}</td>
</tr>
</c:forEach>
</table>
</body>
4、前端通过一个url请求获取数据
业务场景数据表格,点击按钮,获取后台传过来的数据,显示在表格里
一般是将数据打包成json格式给前端
前端需要的数据
{"code":200,"msg":"sucess","count":1000,
"data":[
{"id":10000,"username":"user-0","sex":"女","city":"城市-0"},
{"id":10001,"username":"user-1","sex":"男","city":"城市-1"}]}
code是状态码
msg请求结果
count是数据表格中需要进行分页总数据条数
data是要显示的数据,后端一般是list集合
java servlet类中
List<OInfoEntity> list = orderService.getInfos();
System.out.println(list);
/*通过打印流向前端传输数据*/
/*这里就是传输符合的json数据*/
PrintWriter out = resp.getWriter();
Map<String,Object> resMap = new HashMap<>(); // 使用Map存储键值对
resMap.put("code",200); // 向Map对象中添加内容
resMap.put("msg","sucess");
resMap.put("count","10");
String resJSON = JSON.toJSONString(resMap); // 转换为json
out.print(resJSON); // 输出
map转换为json的依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
实际项目中,我们通常会封装一个响应类配合分页插件向前端响应数据
R类
/**
* 返回数据
* R 继承了 HashMap 则不能继续使用泛型数据了 必须全是hashMap数据
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
/**
* @param key 获取指定key的名字
*/
public <T> T getData(String key, TypeReference<T> typeReference){
// get("data") 默认是map类型 所以再由map转成string再转json
Object data = get(key);
return JSON.parseObject(JSON.toJSONString(data), typeReference);
}
/**
* 复杂类型转换 TypeReference
*/
public <T> T getData(TypeReference<T> typeReference){
// get("data") 默认是map类型 所以再由map转成string再转json
Object data = get("data");
return JSON.parseObject(JSON.toJSONString(data), typeReference);
}
public R setData(Object data){
put("data", data);
return this;
}
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系FIRENAY");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
public Integer getCode() {
return (Integer) this.get("code");
}
}
分页工具类
/**
* 分页工具类
*
*/
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
private int totalCount;
/**
* 每页记录数
*/
private int pageSize;
/**
* 总页数
*/
private int totalPage;
/**
* 当前页数
*/
private int currPage;
/**
* 列表数据
*/
private List<?> list;
/**
* 分页
* @param list 列表数据
* @param totalCount 总记录数
* @param pageSize 每页记录数
* @param currPage 当前页数
*/
public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
this.list = list;
this.totalCount = totalCount;
this.pageSize = pageSize;
this.currPage = currPage;
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
}
/**
* 分页
*/
public PageUtils(IPage<?> page) {
this.list = page.getRecords();
this.totalCount = (int)page.getTotal();
this.pageSize = (int)page.getSize();
this.currPage = (int)page.getCurrent();
this.totalPage = (int)page.getPages();
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getCurrPage() {
return currPage;
}
public void setCurrPage(int currPage) {
this.currPage = currPage;
}
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}
}
参数类
/**
* 查询参数
*
*/
public class Query<T> {
public IPage<T> getPage(Map<String, Object> params) {
return this.getPage(params, null, false);
}
public IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
//分页参数
long curPage = 1;
long limit = 10;
if(params.get(Constant.PAGE) != null){
curPage = Long.parseLong(params.get(Constant.PAGE).toString());
}
if(params.get(Constant.LIMIT) != null){
limit = Long.parseLong((String)params.get(Constant.LIMIT));
}
//分页对象
Page<T> page = new Page<>(curPage, limit);
//分页参数
params.put(Constant.PAGE, page);
//排序字段
//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));
String order = (String)params.get(Constant.ORDER);
//前端字段排序
if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
if(Constant.ASC.equalsIgnoreCase(order)) {
return page.addOrder(OrderItem.asc(orderField));
}else {
return page.addOrder(OrderItem.desc(orderField));
}
}
//没有排序字段,则不排序
if(StringUtils.isBlank(defaultOrderField)){
return page;
}
//默认排序
if(isAsc) {
page.addOrder(OrderItem.asc(defaultOrderField));
}else {
page.addOrder(OrderItem.desc(defaultOrderField));
}
return page;
}
}
五、cookie与session
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session,
由于HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话,所以有会话跟踪技术。
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
简单理解:登陆网站之后,关闭浏览器,下次登陆,就不需要登陆了,这就是会话(Session)跟踪。
使用
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*获取浏览器上所有的cookie*/
Cookie[] cookies = req.getCookies();
boolean flag = false;
if(cookies != null){
for (Cookie cookie:cookies) {
/*循环遍历找到名是lastTime的cookie*/
if(cookie.getName().equals("lastTime")){
/**cookie.getValue取出值*/
long time = Long.parseLong(cookie.getValue());
Date d = new Date(time);
flag = true;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatTime = sdf.format(d);
/*打印名是cookie的值*/
resp.getWriter().println("上一次你访问的时间是:" + formatTime);
break;
}
}
}
if(false){
resp.getWriter().println("你是第一次访问我们的网站....谢谢您!");
}
/*添加一个cookie*/
Cookie cookie = new Cookie("lastTime",System.currentTimeMillis() + "");
/*设置cooki的有效时间,单位秒*/
cookie.setMaxAge(60);
/**cookie.setMaxAge(0) 删除cookie,也可以浏览器手动删除*/
resp.addCookie(cookie);
}
Session在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
doPost或doGet方法
/*获取session*/
HttpSession session = req.getSession();
/*向session里面写入数据*/
session.setAttribute("userName","王一辉");
/*从session拿出数据*/
String s = (String) session.getAttribute("userName");
/*获得sessionID*/
String sessionID = session.getId();
jsp拿到session里面userName的值
${sessionScop.userName}
区别:
1、数据存放位置不同:
cookie数据存放在客户的浏览器上,session数据放在服务器上。
filter过滤器
xml
<filter>
<filter-name>TestFilter1</filter-name>
<filter-class>com.yingside.filter.TestFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>TestFilter1</filter-name>
<url-pattern>/*</url-pattern>
类实现Filter,重写destory(),doFilter(),init()方法
public class TestFilter1 implements Filter {
public void destroy() {
System.out.println("----TestFilter1.destroy----");
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
System.out.println("TestFilter1.doFilter1111111");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
System.out.println("======TestFilter1.init======");
}
}
配置类写法(自动登陆功能)
@WebFilter(filterName = "AutoLoginFilter",urlPatterns = "*.do")
public class AutoLoginFilter implements Filter {
private UserDao mapper = null;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse) resp;
HttpSession session = request.getSession();
Object u = session.getAttribute("user");
if(u != null){
chain.doFilter(req, resp);
return;
}
Cookie[] cookies = request.getCookies();
String value = null;
if(cookies != null){
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if(cookie.getName().equals("autoLogin")){
value = cookie.getValue();
break;
}
}
if(value != null){
String[] s = value.split("_");
String username = s[0];
String password = s[1];
User user = mapper.login(username,password);
if(user != null){
session.setAttribute("user",user);
}
}
}
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
String s = "mybatis-config.xml";
InputStream ins = this.getClass().getClassLoader().getResourceAsStream(s);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(ins);
SqlSession sqlSession = factory.openSession();
mapper = sqlSession.getMapper(UserDao.class);
}
}
Listener监听器
Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。就可以实现当前在线人数的功能。
监听对象:
1、ServletContext:application,整个应用只存在一个
2、HttpSession:session,针对每一个对话
3、ServletRequest:request,针对每一个客户请求
创建步骤:
1、创建一个实现监听器接口的类
2、配置web.xml文件,注册监听器
<listener>
<listener-class>完整类名</listener-class>
</listener>
注意:
监听器的启动顺序:按照web.xml的配置顺序来启动
加载顺序:监听器>过滤器>Servlet