搭建一个JavaWeb项目流程
本文致力于,让编程者一步步明白书写一个JavaWeb项目应该做些什么,梳理清楚流程框架,需要的jar包,同时手写了一个分页工具类也在其中,让你在编程中更加丝滑。
1.src\main\java\com\einmeer\qianyu
删除系统默认生成的
HelloServlet.java
1.1tools包
DruidTools.java
需要在
lib
中加入druid-1.1.22.jar
package com.einmeer.qianyu.tools;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author 芊嵛
* @date 2024/1/18
* JDBC操作,就是在java中操作数据库
* 封装数据库连接工具,带连接池的
*/
public class DruidTools {
//声明连接池对象
private static DruidDataSource dataSource;
//java的静态代码块,作初始化用
static {
//读取外部配置文件的内容,生成字节流输入流对象
InputStream in = DruidTools.class.getResourceAsStream("/Druid.properties");
//创建属性集合对象
Properties properties = new Properties();
try {
//加载输入流对象
properties.load(in);
//生成连接池对象
dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取接池对象,便于dbutils使用,简化原生JDBC的增删改查功能CURD
public static DruidDataSource getDataSource(){
return dataSource;
}
//拿到数据库连接对象,便于我们操作MYSQL
public static Connection getConn() {//方便之后重复使用
Connection conn = null;
try {
//创建数据库连接对象(数据库地址,用户名,密码)
conn = dataSource.getConnection();
System.out.println("数据库连接成功success!");
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
测试一下,建议用单元测试
public static void main(String[] args) {
getConn();
}
}
Pagination.java
分页,封装好了方法之后直接调用就行
package com.einmeer.qianyu.tools;
import java.util.List;
/**
* @author 芊嵛
* @date 2024/1/19
*/
public class Pagination<T> { // 使用泛型是为了复用
// 当前页号
private int currentPage;
// 总页号或总页数
private int totalPage;
// 每页记录数或行数
private int limitRows;
// 总的记录数或行数
private int totalRows;
// 每页开始的记录号
private int startRecord;
// 每页结束的记录号,这个没用,只需每页记录行数limitRows即可
// private int endRecord;
// 存每页中的记录
private List<T> list;
// //初始化操作
public void init() {
// 1.求总页数,通过总记录数与每页行数来计算,有几种情况
// (1)不够一页(2)有零头(3)刚好是整数页
int tp = totalRows / limitRows;
if (totalRows > limitRows) {
// 判断是是刚刚好还是一页多一点
totalPage = (totalRows % limitRows) == 0 ? tp : tp + 1;
} else {
totalPage = 1;
}
// 2.将当页保留在第一页或最后一页
if (currentPage > totalPage) {
currentPage = totalPage;
} else if (currentPage < 1) {
currentPage = 1;
}
// 3.初始化开始记录数,mysql应用的limit它不包括开始记录,所以不要加1;
// 还有limit传入的是开始记录号与查询的条数,此处是每页可显示数limitRows,
// 如果查到最后没有limitRows限制的行数,则显示剩余部分
this.startRecord = (currentPage - 1) * limitRows;
}
// 无参构造,便于使用
public Pagination() {
}
// 当前页号,总记录数,每页行数;这些属性需要传入后初始化,其它的可以set设置
public Pagination(int currentPage, int totalRows, int limitRows) {
this.currentPage = currentPage;
this.totalRows = totalRows;
this.limitRows = limitRows;
}
// get与set方法
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getLimitRows() {
return limitRows;
}
public void setLimitRows(int limitRows) {
this.limitRows = limitRows;
}
public int getTotalRows() {
return totalRows;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
public int getStartRecord() {
return startRecord;
}
public void setStartRecord(int startRecord) {
this.startRecord = startRecord;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
1.2entity包
Entity层,实体层,放入实体类
详解Lombok中的@Builder用法
// Lombok注解
@Builder // 一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程,不写@Builder,@AllArgsConstructor会报红
@Data // 提供了get、set、equals、toString方法
@NoArgsConstructor // 生成一个无产构造函数
@AllArgsConstructor // 生成一个包含所有变量的有参构造函数
实现序列化
Serializable接口就是Java提供用来进行高效率的异地共享实例对象的机制,实现这个接口即可。
参考java实体类为什么要实现Serializable接口
implements Serializable
1.3dao包
DAO数据访问层,把访问数据库的代码封装起来,不涉及业务逻辑
// 接口:写需要的细分功能的名字,能用sql语句表示出来,如格局用户id查询用户全部信息
User selectUserById(Long userId);
// 实现类
//1.建议先定义一个全局结果集返回对象,应为每次运行sql语句都会返回结果
QueryRunner qr = new QueryRunner(DruidTools.getDataSource());
// 2.每个接口第一句都把返回值类型置为空(查询语句置为null)或者0(增删改置为0)
List<User> list = null;
int n = 0;
// 3.每个接口第二句写sql语句(我这里举例简单写写*号实际一定不要写*)
String sql = "select * from user where username like ? and userGander = ? limit ?,?";
// 4.创建一个对象类数组(里面放?号代替的东西,注意位置不要错)
// 如果就一个参数或者不需要参数不用写这个,多个参数再写
Object[] param = {"%"+username+"%",userGaner,start,number};
// 5.处理异常,执行sql
try {
// 查询
// 返回list结果集BeanListHandler<>()
// 返回对象BeanHandler<>()
// 返回单个数据ScalarHandler<>()
// query(String sql, ResultSetHandler<T> rsh)
// query(String sql, Object param, ResultSetHandler<T> rsh)
// query(String sql, Object[] params, ResultSetHandler<T> rsh)
// 更多可以看看源码
list = qr.query(sql, new BeanListHandler<User>(User.class));
user = qr.query(sql, param, new BeanHandler<>(User.class));
// 这个看其他资料说是返回Object类型需要转,但是我测试并不需要,返回的就是我要的类型
n = qr.query(sql,parm,new ScalarHandler<>());
// 更新/删除/插入
// update(String sql, Object param)
// update(String sql, Object... params)
n = qr.update(sql, username);
n = qr.update(sql, param);
} catch (SQLException e) {
throw new RuntimeException(e);
}
// 6.return 第一步的名字;
return list;
return n;
1.4service包
Service业务逻辑层,处理逻辑上的业务,而不去考虑具体的实现。
通过调用数据访问层,实现逻辑上的业务,一个接口的实现可能需要多个dao层的接口
// 接口:定义好方法,之后servlet直接调用,与servlet方法数量相同
// 名字最好不要跟dao层一样
// dao:select
// service:query
// 实现类
// 1.全局调一下dao层,方便下面调用
private UserDao userDao = new UserDaoImpl;
// 2.自由发挥
1.5servlet包
Servlet(Server Applet)是Java Servlet的简称,是为小服务程序或服务连接器,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。
// 1.注解,
@WebServlet("/user")
// 2.继承HttpServlet
public class UserServlet extends HttpServlet{}
// 3.创建服务类对象
private UserService userService = new UserServiceImpl();
// 4.重写doGet()方法,如果调用它就会调用doPost()方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
// 5.重写doPost()方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 首局一定要写这句,把用户传来的数据如果有汉字转为汉字,不然乱码
req.setCharacterEncoding("utf8");
// 这里我前端页面隐藏了一个表单,区分页面传入的是哪个方法
// <input type="hidden" name="method" value="pn-prid">
String method = req.getParameter("method");
// 根据method判断需要调用什么方法
}
// 6.具体方法,举一个例子
public void queryAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 前端传来的参数
String proCode = req.getParameter("queryProCode");
String proName = req.getParameter("queryProName");
Object current = req.getParameter("current");
// 实现分页(当时划分不清楚,这块感觉可以写进service进行封装)
int temp1 = 0;
if (current != null) {
temp1 = Integer.parseInt(req.getParameter("current"));
}
long temp = ps.queryCount(proCode,proName);
int totalRows = (int) temp;
Pagination<Provider> pg = new Pagination<>(temp1, totalRows, 10);
pg.init();
List<Provider> providers = ps.queryLimit(proCode,proName,pg.getStartRecord(), 10);
pg.setList(providers);
// 携带数据请求转发
RequestDispatcher rd = req.getRequestDispatcher("WEB-INF/jsp/providerlist.jsp");
// 携带数据
req.setAttribute("p1",proCode);
req.setAttribute("p2",proName);
req.setAttribute("providers", pg.getList());
req.setAttribute("pg", pg);
rd.forward(req, resp);
}
2.src\main\resources
druid.properties
# 如果mysql是5版本的去掉cj
driverClassName=com.mysql.cj.jdbc.Driver
# 端口号默认3306如果修改了记得把此处进行修改
# 记得修改数据库的名字
url=jdbc:mysql://localhost:3306/数据库名字?rewriteBatchedStatements=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
# 数据库账号,根据实际填写
username=root
# 数据库密码,根据实际填写
password=quanyu9988.gmail.com
# 一般不需要更改,初始化数据库连接池
initialSize=10
# 一般不需要更改,连接池的最大数据库连接数
maxActive=20
# 一般不需要更改,超时等待时间一毫秒为单位
maxWait=1000
# 一般不需要更改,连接池的最小空闲连接数,如果空闲的连接数大于该值,则关闭多余连接,反之创建更多连接满足最小连接数的要求
minIdle=5
3.src\main\webapp
3.1WEB-INF\lib
// 不导入,连接池用不了
druid-1.1.22.jar
// 导入可以使用QueryRunner类+ResultSetHandler类,更方便的完成curd
commons-dbutils-1.7.jar
// 数据库驱动,我这里用的8
mysql-connector-java-8.0.25.jar
//使用JSTL核心标签库,需要导入下面两个依赖
standard.jar
jstl.jar
3.2WEB-INF\jsp
存放无法直接在地址栏访问的界面
3.3WEB-INF\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_4_0.xsd"
version="4.0">
<!--欢迎页,也就是一启动就能看见的页面-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
3.4暴露在外面的内容
例如:
css
js
images以及能直接在地址栏访问的界面
login.jsp
register.jsp下面jsp页面第八行必须写上,才能证明他是jsp页面
<%--
Created by IntelliJ IDEA.
User: Qy
Date: 2024/1/18
Time: 20:42
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--如果用到了核心标签记得加上核心标签库--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
<%--所有外面的静态资源一定要用<%=request.getContextPath()%>代替..不然找不到数据--%>
<link type="text/css" rel="stylesheet" href="<%=request.getContextPath()%>/css/style.css"/>
</head>
<body>
</body>
</html>
4.pom.xml
这份说明没用到maven,采取自己导入jar包,这么的代码没有修改只是作为说明
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- maven的基本信息-->
<modelVersion>4.0.0</modelVersion>
<!-- 声明遵循哪一个pom模型版本-->
<!-- 组织表示,一般是公司网站倒过来-->
<groupId>com.einmeer</groupId>
<!-- 本项目的唯一标识ID,项目名称-->
<artifactId>qianyu</artifactId>
<!-- 项目当前版本号-->
<version>1.0-SNAPSHOT</version>
<!-- 右边maven名字-->
<name>qianyu</name>
<!-- 打包方式-->
<packaging>war</packaging>
<!-- POM之间的关系-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.9.2</junit.version>
</properties>
<!-- 依赖关系列表-->
<dependencies>
<!-- 自己添加的lombok可以让我们在写实体类的时候大大减少代码量-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<!-- 依赖项的组织名-->
<groupId>javax.servlet</groupId>
<!-- 依赖项的子项目名-->
<artifactId>javax.servlet-api</artifactId>
<!-- 依赖项的版本-->
<version>4.0.1</version>
<!-- 依赖项的适用范围-->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 构建设置-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
</project>