1 文件上传和文件下载
1.1 文件上传
- 创建jsp页面 表单和文件上传元素 声明表单属性 enctype=“mulitiper/form-data”;
- 创建servlet 声明注解@MultipartConfig 表示此servlet支持文件上传;
- .声明路径;
- 对路径进行判断 不过不存在 则新建一个;
- 获取Part对象 request.getPart;
- 写一个提取文件名称的方法 (参数 part) 获取并拆分头信息,拿到其中的filename;
- 通过获取文件名称的方法提取文件名;
- part.write写入指定路径;
- 给返回信息;
声明上传页面
<%--
Created by IntelliJ IDEA.
User: 14408
Date: 2023/2/17
Time: 14:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/testdemo/upload" method="post" enctype="multipart/form-data">
<input type="file" name="filename">
<input type="submit" name="submit">
</form>
</body>
</html>
文件上传接口
package net.lizheng.web.File.FileDownload;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDate;
import java.util.UUID;
@WebServlet(name = "Fileupload",value = "/upload")
@MultipartConfig
public class FileUpload extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Part对象
Part filename = req.getPart("filename");
//获取当前日期
LocalDate now=LocalDate.now();
//获取uuid
UUID uuid = UUID.randomUUID();
//如果dirFile不存在则创建目录
String dir="D:\\提升学习巩固基础\\javaWeb\\newproject\\web\\";
File dirFile = new File(dir+now);
if(!dirFile.exists()){
dirFile.mkdir();
}
filename.write(dirFile+"\\"+uuid+".jpg");
//验证文件是否上传成功
File dirFile1=new File(dirFile+"\\"+uuid+".jpg");
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
if (dirFile1.exists()){
writer.write("文件上传成功");
}else {
writer.write("文件上传失败");
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
1.2 文件下载
- 通过超链接,在连接地址⾥里里写上⽂文件的路路径,浏览器器会⾃自动打开该⽂文件;
- 普通的⽂文本,图⽚片等浏览器能直接显示内容的浏览器都能直接打开并显示;
- 如果是浏览器器⽆无法打开的文件,比如exe等浏览器就会提示你下载改文件或者使用当前系统自带的⼯工具打开该文件;
后端开发
package net.lizheng.web.File.Fileupload;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "Filedown",value = "/down")
public class FileDown extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//文件目录
String dir="D:\\提升学习巩固基础\\javaWeb\\newproject\\web\\2023-02-17\\";
//获取日期
String Filename = req.getParameter("Filename");
//设置编码格式
resp.setContentType("text/html;charset=utf-8");
//确定目录文件是否存在
File file=new File(dir+Filename);
if (file.exists()){
//读取当前文件下
String[] list = file.list();
//读取文件
FileInputStream fileInputStream=new FileInputStream(file);
resp.setHeader("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes(), "ISO-8859-1"));
//获取输出流对象
ServletOutputStream outputStream = resp.getOutputStream();
byte [] bytes=new byte[1024];
int a=0;
while ((a=(fileInputStream.read(bytes)))!=-1){
outputStream.write(bytes);
}
fileInputStream.close();
outputStream.close();
}else {
final PrintWriter writer = resp.getWriter();
writer.write("文件不存在");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
前端开发
<%--
Created by IntelliJ IDEA.
User: 14408
Date: 2023/2/20
Time: 9:55
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件下载</title>
</head>
<body>
<a href="http://localhost:8080/testdemo/down?Filename=192dbb2b-e54c-4742-8d8a-13b4c0c4c664.jpg">文件下载</a>
</body>
</html>
2 三层目录结构和MVC
2.1 什么是mvc
- model:承载数据的bean,就是order对象,例如order/user的实体类 、service、dao层。
- view:页面例如jsp,直接面对用户,和用户进行交互。
- cotroller:将用户的请求转发给model进行处理,根据model的处理结果响应给view。
2.2 三层架构
- 软件包
- 不同的软件实现不同的功能;
- 降低了各层的耦合性,在三层模型的程序设计使用的是抽象设计;
- 上层对下层的调用,是通过的多态实现的;
- 下层对上层的真正的提供者,是下层的实现类;
- 视图层 也叫view层
- 接受用户的请求
- 服务层Service
- 系统的业务逻辑
- 持久层 Dao
- 操作数据库的代码
- 操作数据库的代码
2.3 互联网公司src的常见目录
- controller 控制层;
- service 业务层;
- dao 数据操作层;
- domain 实体层 ;
- util 工具类;
- listener 监听层;
- filtter 过滤层;
- config配置类;
3 JDBC技术
3.1 什么是JDBC
- JDBC 全称是Java Database Connectivity 是Java语言 规范客户端程序访问数据库的规范;
- 是一种基准接口,提供了更高级的工具和接口,让数据库开发人员能够开发数据库应用程序;
- 应用程序不能直接访问数据库,需要使用数据库驱动;
- 什么是数据库驱动:可以理解为数据库厂商对接口的实现;
- JDBC的相关概念
- 什么是数据库驱动:是数据库厂商为了让开发语言访问数据库而设计的应用程序;
- connection:数据库连接(会话) ,连接上下文,执行sql并取得结果集;
- statement:需要执行的sql;
- results 结果集;
- JDBC的调用流程
- 加载JDBC;
- 建立Connction;
- 执行Satement;
- 取得Results;
- 释放资源 ;
3.2 JDBC 连接数据库
- 需要下载数据库驱动jar包,不同的版本需要对应不同jar包,笔者5.这点使用的数据库5.7 对应的驱动是mysql-connector-java-5.1.46.jar
- ResultSet的常用方法
package net.lizheng.jdbc;
import java.sql.*;
public class JDBCConnection {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//账号
String user="root";
//密码
String passwd="lz123456";
//地址
String url="jdbc:mysql://192.168.31.212:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
//获取connect对象
Connection connection= DriverManager. getConnection(url,user,passwd);
//获取Statement对账
Statement statement =connection.createStatement();
//获取ResultSet结果
ResultSet resultSet = statement.executeQuery("select * from user");
//根据resultSet的油标获取结果集
while(resultSet.next()){
System.out.println("id:"+resultSet.getInt(1)+"电话号码是"+resultSet.getString(2)+"密码是"+resultSet.getString(3));
}
//释放资源
resultSet.close();
statement.close();
connection.close();
}
}
3.3 SQL注入和预编译
- SQL注入 :恶意插入SQL.把任意SQL语句插入到查询中,修改或者插入表的记录;
- 预编译:也叫预声明,对SQL语句语句进行预编译,参数使用占位符?填充
- 在第一次操作数据的时候,数据库会对SQL语句解析和分析, 并缓存执行计划,参数使用参数化的方式,这样就保证了值传入的是一个值而不是sql;
例如:sql注入(通过查询一条数据而查询出了整张表的数据);
- 在第一次操作数据的时候,数据库会对SQL语句解析和分析, 并缓存执行计划,参数使用参数化的方式,这样就保证了值传入的是一个值而不是sql;
package net.lizheng.jdbc;
import java.sql.*;
public class JDBCConnection {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//账号
String user="root";
//密码
String passwd="lz123456";
//地址
String url="jdbc:mysql://192.168.10.154:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
//获取connect对象
Connection connection= DriverManager. getConnection(url,user,passwd);
//获取Statement对账
Statement statement =connection.createStatement();
//把username参数改动就能查看整张表的数据
String username="username='张三' OR 1=1";
//获取ResultSet结果
ResultSet resultSet = statement.executeQuery("select * from user where username="+username);
//根据resultSet的油标获取结果集
while(resultSet.next()){
System.out.println("id:"+resultSet.getInt(1)+"电话号码是"+resultSet.getString(2)+"密码是"+resultSet.getString(3));
}
//释放资源
resultSet.close();
statement.close();
connection.close();
}
}
预编译(使用参数化的方式)
package net.lizheng.jdbc;
import java.sql.*;
public class JdbcConnectionPre {
public static void main(String [] args) throws SQLException, ClassNotFoundException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//账号
String user="root";
//密码
String passwd="lz123456";
//地址
String url="jdbc:mysql://192.168.10.154:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
//获取connect对象
Connection connection= DriverManager. getConnection(url,user,passwd);
//获取preStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from user where username=?");
//参数化
preparedStatement.setString(1,"张三");
ResultSet resultSet = preparedStatement.executeQuery();
//根据resultSet的油标获取结果集
while(resultSet.next()){
System.out.println("id:"+resultSet.getInt(1)+"电话号码是"+resultSet.getString(2)+"密码是"+resultSet.getString(3));
}
//释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
}
3.4 JDBC操作插入和删除
插入
package net.lizheng.jdbc;
import java.sql.*;
public class JdbcConnectionInsert {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//账号
String user="root";
//密码
String passwd="lz123456";
//链接
String url="jdbc:mysql://192.168.31.212:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
//获取connection对象
Connection connection = DriverManager.getConnection(url, user, passwd);
//获取预编译PreparedStatement
PreparedStatement preparedStatement = connection.prepareStatement("insert into user values(?,?,?,?,?,?,?,?,?)");
//设置参数
preparedStatement.setInt(1,7);
preparedStatement.setString(2,"18716645598");
preparedStatement.setString(3,"123456");
preparedStatement.setInt(4,2);
preparedStatement.setString(5,"159357");
preparedStatement.setTimestamp(6,new Timestamp(System.currentTimeMillis()));
preparedStatement.setString(7,"2");
preparedStatement.setString(8,"小曾");
preparedStatement.setString(9,"123456");
//执行
preparedStatement.execute();
//释放资源
preparedStatement.close();
connection.close();
}
}
删除
package net.lizheng.jdbc;
import java.sql.*;
public class JdbcConnectionInsert {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//账号
String user="root";
//密码
String passwd="lz123456";
//链接
String url="jdbc:mysql://192.168.31.212:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
//获取connection对象
Connection connection = DriverManager.getConnection(url, user, passwd);
//获取预编译PreparedStatement
PreparedStatement preparedStatement = connection.prepareStatement("delete from user where id=?");
//设置参数
preparedStatement.setInt(1,1);
//执行
preparedStatement.execute();
//释放资源
preparedStatement.close();
connection.close();
}
}
3.5 JDBC与mysql事务
- 事务:一个最小不可再分的工作单元,一个事务对应一个最小的业务,例如:买票;
- 事务的特点
- 原子性;最小的工作单元,不可再分;
- 一致性;操作的DML语句,要么全部执行成功,要么全部失败;
- 隔离性;事务a和事务b的隔离;
- 持久性:事务成功的标志,是数据是否成功被写入到持久化设备;
- 事务的相关概念
- start transcation 开始事务;
- end transcation 结束事务;
- commit transcation 提交事务;
- rollback transcation 回滚事务;
package net.lizheng.jdbc;
import java.sql.*;
public class JdbcConnectionInsert {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//账号
String user="root";
//密码
String passwd="lz123456";
//链接
String url="jdbc:mysql://192.168.31.212:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false";
//获取connection对象
Connection connection = DriverManager.getConnection(url, user, passwd);
//不设置自动提交
connection.setAutoCommit(false);
;
try{
//获取预编译PreparedStatement1
PreparedStatement preparedStatement1 = connection.prepareStatement("delete from user where id=?");
//执行会报错
PreparedStatement preparedStatement2 = connection.prepareStatement("delete from user where id=");
//设置参数
preparedStatement1.setInt(1,5);
//设置不存在的参数报错
preparedStatement2.setString(1,"df");
//执行
preparedStatement1.execute();
preparedStatement2.execute();
}catch (Exception e){
e.printStackTrace();
//回滚事务
connection.rollback();
}finally {
//释放资源
connection.commit();
connection.close();
}
}
}
4 JDBC操作数据库的工具类和池化思想
4.1 自行封装工具类
- 编写配置文件jdbc.properties
package net.lizheng.web.Utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class SelfJdbcbUtil {
private static String user;
private static String passwd;
private static String url;
private static String dirver;
//加载初始化参数
static {
try {
//读取文件的类Properties
Properties properties=new Properties();
//加载文件
InputStream resourceAsStream = SelfJdbcbUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(resourceAsStream);
//获取参数
user=properties.getProperty("user");
passwd=properties.getProperty("passwd");
url=properties.getProperty("url");
dirver=properties.getProperty("dirver");
Class.forName("com.mysql.jdbc.Driver");
} catch (Exception e ) {
e.printStackTrace();
}
}
//获取链接
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url, user, passwd);
return connection;
}
//关闭链接
public void close(PreparedStatement preparedStatement, Connection connection, ResultSet resultSet){
try {
preparedStatement.close();
connection.close();
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.2 池化思想
- 池化思想:一般用于对象池化,核心思想是空间换时间,期望用预先创建好了对象,来减少对象的创建和销毁,同时也有利于统一的管理和维护;
- 数据库池化思想
- 数据库的创建connection会造成大量的性能消耗;
- 数据库的connection的复用,就可以减少性能消耗,保证系统的稳定;
- 数据库的池初始化的过程中,就会创建若干connection在池中,业务处理逻辑时直接使用;
- 对池的统一管理,要避免connection的泄露和超时;
5 数据库连接池和apache dbUtils实战
5.1 常用的Jdbc的工具类和数据库连接池;
- apache comments dbUtils 是apache公司开发的一款jdbc的工具类,对jdbc进行了简单的封装不影响性能;
- 下载地址:https://commons.apache.org/proper/commons-dbutils/
- 常用的数据库连接池:
- c0p3、druid、dbcp;
- dbcp的全称是database connection pool 是apache下的一款数据库连接池工具;
5.2 dbUtils 和dbcp建立连接池
- 需要4个包
- commons-dbcp2-2.7.0.jar;
- commons-dbutils-1.7.jar;
- commons-logging-1.2.jar;
- commons-pool2-2.8.0.jar;
- properties文件
- initialSize是连接池的初始化数;
- maxActive是连接池最大数;
driverClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://192.168.10.154:3306/studytest?useUnicode=true&characterEncoding=utf-8&useSSL=false
username = root
password = lz123456
initialSize=2
maxActive=15
package net.lizheng.web.Utils;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.util.Properties;
public class dbcpUtils {
private static DataSource dataSource;
static {
Properties properties=new Properties();
InputStream resourceAsStream = dbcpUtils.class.getClassLoader().getResourceAsStream("apchedbcp.properties");
try {
properties.load(resourceAsStream);
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource(){
return dataSource;
}
}
5.3 dbUtils的核心类
- QueryRunner 提供了执行sql语句的api,核心方法2个;
- update(String sql ,Object …param) 执行插入,删除,更新语句 ;
- query(String sql,ResultsetHandler re, Object …param ) 对查询结果进行处理
- ResultsetHandler 对结果处理的接口
- BeanHandler 把查询的第一条结果,封装到对应的Javabean;
- BeanListHandler 把每一条查询的结果,封装到对应的Javabean,并存入到List里面;
- MapHandler 查询的第一条结果,封装到对应的map中;
- MapListHandler 查询的每一条结果,封装到对应的map中,并放入对应的list中;
- ScalarHandler 对结果查询的值,主要用于单值查询;
5.3.1 BeanHandler、BeanListHandler、MapHandler MapListHandler
dao层代码
package net.lizheng.web.Dao;
import net.lizheng.web.Utils.dbcpUtils;
import net.lizheng.web.doamain.UserBean;
import org.apache.commons.dbutils.*;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
public class UseInfoSelect {
private BeanProcessor bean = new GenerousBeanProcessor();
private RowProcessor processor = new BasicRowProcessor(bean);
private QueryRunner queryRunner=new QueryRunner(dbcpUtils.getDataSource());
//使用beanhandler的方式处理结果集
public UserBean getUserInfo(String name) {
String sql="select * from user where username=?";
UserBean userBean=null;
try {
userBean = queryRunner.query(sql, new BeanHandler<>(UserBean.class, processor), name);
}catch (SQLException e ){
e.printStackTrace();
}
return userBean;
};
//使用beanlisthandler的方式处理结果集合;
public List<UserBean> getUserList() {
String sql="select * from user";
List<UserBean> listUserBean=null;
try {
listUserBean = queryRunner.query(sql, new BeanListHandler<>(UserBean.class, processor));
}catch (SQLException e ){
e.printStackTrace();
}
return listUserBean;
}
//使用maphandler处理结果集合
public Map<String, Object> mapUserInfo(String name){
String sql="select * from user where username=?";
Map<String, Object> userinfo =null;
try {
userinfo = queryRunner.query(sql, new MapHandler(), name);
}catch (SQLException e){
e.printStackTrace();
}
return userinfo;
}
//使用maplisthandler处理结果集合
public List<Map<String, Object>> mapListUserInfo(){
List<Map<String, Object>> alluserinfo=null;
String sql="select * from user";
try {
alluserinfo = queryRunner.query(sql, new MapListHandler());
}catch (SQLException e){
e.printStackTrace();
}
return alluserinfo;
}
}
controller层代码
package net.lizheng.web.controller;
import net.lizheng.web.doamain.UserBean;
import net.lizheng.web.service.imp.UserInfoService;
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;
import java.util.Map;
@WebServlet(urlPatterns = {"/userinfo"})
public class UserInfoFindName extends HttpServlet {
UserInfoService userInfoService =new UserInfoService();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.addHeader("Content-Type","text/html;charset=utf-8");
UserBean beaninfo1 = userInfoService.getName("小曾");
List<UserBean> beaninfo2 = userInfoService.getList();
Map<String, Object> mapinfo1 = userInfoService.getMapUserInfo("小政");
List<Map<String, Object>> maplistinfo2 = userInfoService.getMapListUserInfo();
PrintWriter printwriter = resp.getWriter();
printwriter.write("BeanHandler处理结果"+beaninfo1.toString()+"\n"+"\t"
+"BeanListHandler处理结果"+beaninfo2.toString()+"\n"+"\t"
+"MapHandler处理结果"+mapinfo1.toString() +"\n"+"\t"
+"MapListHandler处理结果"+maplistinfo2.toString());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}