返回上一个链接的写法
- 当点击链接到一个页面的时候,点击返回,原路返回,也不用直接重新查询的写法
<input class="button_ok" type="button" onclick="history.go(-1)"
value="返回"/>
分页模板
使用该分页模板,变量名字必须的当前一样
将分页信息PageMode保存在request作用域中,必须用pageBean
request.setAttribute("pageBean",pageMode); currentPage //当前页
这两个变量的名称必须一样,否则再pageFile.jsp中获取不到相应的数据,在url上的当前页的参数名必须是currentPage,否则后台request.getParameter() 获取不到数据
totalPage //总页数
pageSize //当前页的记录数 ,自己定义
totalSize //总记录数 ,根据查新数据库得到
prePage //上一页
nextPage //下一页
startPage //起始页码
endPage //结束页码
startIndex //起始索引
url //url地址,作用在点击页数上的链接,不包括参数currentPage
例如:
pageMode.setUrl("/AdminProductServlet?method=findAllProductsWithPage");
- pageFIle.jsp (前端显示的分页)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>关于我们</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css" type="text/css" />
<script src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js" type="text/javascript"></script>
<!-- 引入自定义css文件 style.css -->
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css" type="text/css"/>
</head>
<body>
共${pageBean.totalPage}页/第${pageBean.currentPage}页
<a href="${pageContext.request.contextPath}/${pageBean.url}¤tPage=1">首页</a>
<a href="${pageContext.request.contextPath}/${pageBean.url}¤tPage=${pageBean.prePage}">上一页</a>
<%--显示的页码,使用forEach遍历显示的页面 --%>
<c:forEach begin="${pageBean.startPage}" end="${pageBean.endPage}" var="pagenum">
<a href="${pageContext.request.contextPath}/${pageBean.url}¤tPage=${pagenum}">${pagenum}</a>
</c:forEach>
<a href="${pageContext.request.contextPath}/${pageBean.url}¤tPage=${pageBean.nextPage}">下一页</a>
<a href="${pageContext.request.contextPath}/${pageBean.url}¤tPage=${pageBean.totalPage}">末页</a>
<input type="text" id="pagenum" name="pagenum" size="1"/>
<input type="button" value="前往" onclick="jump()" />
<script type="text/javascript">
function jump(){
var totalpage = ${pageBean.totalPage};
var pagenum = document.getElementById("pagenum").value;
//判断输入的是一个数字
var reg =/^[1-9][0-9]{0,1}$/;
if(!reg.test(pagenum)){
//不是一个有效数字
alert("请输入符合规定的数字");
return ;
}
//判断输入的数字不能大于总页数
if(parseInt(pagenum)>parseInt(totalpage)){
//超过了总页数
alert("不能大于总页数");
return;
}
//转向分页显示的Servlet
window.location.href="${pageContext.request.contextPath}/${pageBean.url}¤tPage="+pagenum;
}
</script>
</div>
<%--分页显示的结束--%>
</body>
</html>
- PageMode.java
package com.domain;
import java.util.List;
public class PageMode<T> {
private int currentPage; //当前页 前端传入过来的参数,默认当前页为1
private int totalPage; //总页数 总记录数/当前页记录数
private int pageSize; //当前页记录数 这个根据前端显示几个自己定义
private int totalSize; //总记录数 查询数据库得到
private List<T> list; //当前页的商品,查询数据库得到
//------扩展属性----------------------------------------
private int startIndex; //起始索引
private String url; //url地址
private int prePage; //上一页
private int nextPage; //下一页
private int startPage; //起始页码
private int endPage; //结束页码
public PageMode(int currentPage, int pageSize, int totalSize) {
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalSize = totalSize;
this.list = list;
int sum = totalSize/pageSize;
this.totalPage = (totalSize%pageSize == 0) ? sum : sum+1 ;
this.startIndex = (currentPage-1)*pageSize;
if(totalPage > 9){
//总页数大于9页
this.startPage = currentPage - 4; //5
if(startPage < 1){
startPage = 1;
}
this.endPage = startPage + 8;
if(endPage > totalPage){
endPage = totalPage;
startPage = endPage - 8;
}
}else {
//总页数小于等于9页
this.startPage = 1;
this.endPage = 9;
}
}
public int getPrePage() {
prePage = currentPage - 1;
if(prePage < 1){
//为第一页,首页
prePage = 1;
}
return prePage;
}
public void setPrePage(int prePage) {
this.prePage = prePage;
}
public int getNextPage() {
nextPage = currentPage + 1;
if(nextPage > totalPage){
//为最后一页,末页
nextPage=totalPage;
}
return nextPage;
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
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 getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
@Override
public String toString() {
return "PageMode{" +
"currentPage=" + currentPage +
", totalPage=" + totalPage +
", pageSize=" + pageSize +
", totalSize=" + totalSize +
", list=" + list +
'}';
}
}
工厂模式解耦
当一个项目开发完之后,卖给客户,不确定客户使用的是mysql数据库,还是oracle数据库或者其他的数据库。
每个数据库的sql语句还是有些区别的,所以我们使用application.xml配置文件,根据不同的数据库,写入不同的dao层
前提是你必须完成了每种数据库dao层的实现。
UserDao userDao = new UserDaoImpl();
其实将这种直接new 对象的写法使用配置文件,利用反射来完成
UserDao UserDao=(UserDao)BeanFactory.createObject("UserDao");
//BeanFactory //自己定义的类和其中的方法
还需要用到dom4j
- BeanFactory.java
public class BeanFactory {
//解析XML
public static Object createObject(String name) {
try {
//通过传递过来的name获取application.xml中name对应的class值
//获取到Document对象
SAXReader reader=new SAXReader();
//如果获取application.xml文件的输入流 (application.xml必须位于src下)
InputStream is=BeanFactory.class.getClassLoader().getResourceAsStream("application.xml");
Document doc=reader.read(is);
//通过Document对象获取根节点 beans
Element rootElement = doc.getRootElement();
//通过根节点获取到根节点下所有的子节点 bean,返回集合
List<Element> list = rootElement.elements();
//遍历集合,判断每个元素上的id的值是否和当前的name一致
for (Element ele : list) {
//ele相当于beans节点下的每个bean
//获取到当前节点的id属性值
//如果一致,获取到当前元素上class属性值
String id=ele.attributeValue("id");
if(id.equals(name)){
String str=ele.attributeValue("class");
//通过反射创建对象并且返回
Class clazz=Class.forName(str);
//利用class值通过反射创建对象返回
return clazz.newInstance();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws SQLException {
UserDao ud=(UserDao)BeanFactory.createObject("UserDao");
User user=new User();
user.setUsername("aaa");
user.setPassword("aaa");
User uu = ud.userLogin(user);
System.out.println(uu);
}
}
- applicaion.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="CategoryDao" class="cn.itcast.store.dao.daoImp.CategoryDaoImp"/>
<bean id="UserDao" class="cn.itcast.store.dao.daoImp.UserDaoImp"/>
<bean id="ProductDao" class="cn.itcast.store.dao.daoImp.ProductDaoImp"/>
</beans>
注意:UserDao ud=(UserDao)BeanFactory.createObject(“UserDao”);
传递的参数必须和application.xml文件中id属性值一致才可以
文件(图片)的上传和下载
主要是在标签中加入 ==enctype=“mutipart/form-data” ==属性,如果没有设置enctype浏览器是无法将文件自身传递到服务端
结论: 1_如果设置了mutipart/form-data,在服务端是无法通过request.getParameter(name);
获取数据 2_可以通过request.getInputStream();获取请求体部分的数据 手动实现上传可行性是可以的.
注意如果设置了表单form标签的enctype属性之后,请求体部分的内容的格式发生更改
传统的方式:
username=tom&password=1234&userhead=11.bmp
加入enctype="mutipart/form-data"之后:
POST /TestUpload/ServletDemo01 HTTP/1.1 请求头 ------ 请求体:如下
content-Type: multipart/form-data;
boundary=---------------------------289271763422208 Content-Length:
12517-----------------------------289271763422208 Content-Disposition: form-data; name=“username”
11111
-----------------------------289271763422208 Content-Disposition: form-data; name=“password”22222
-----------------------------289271763422208 content-Disposition: form-data; name=“userhead”; filename=“11.bmp” content-Type: image/bmpBMV/二进制乱码数据,代表图片自身自身自身自身自身自身自身自身自身自身自身自身自身
BMV/二进制乱码数据,代表图片自身自身自身自身自身自身自身自身自身自身自身自身自身
BMV/二进制乱码数据,代表图片自身自身自身自身自身自身自身自身自身自身自身自身自身
BMV/二进制乱码数据,代表图片自身自身自身自身自身自身自身自身自身自身自身自身自身
BMV/二进制乱码数据,代表图片自身自身自身自身自身自身自身自身自身自身自身自身自身
BMV/二进制乱码数据,代表图片自身自身自身自身自身自身自身自身自身自身自身自身自身
-----------------------------289271763422208–
标黄色的是要传的数据,图片数据是一推二进制。
如何在后端获取?
只有根据request.getInputStream();获得所有的数据字符串,然后进行拆分,获得我们想要的数据。
幸好有别人写好的工具类,简化了这一过程
使用利用commons-fileupload-1.2.1.rar实现上传
问题:
1. 如果文件重名发生覆盖问题
解决方法:UUID
2. 同目录下文件/目录过多,性能问题
在images下最多创建16个目录,任意一个目录进入之后最多创建16个目录,
最多创建8层目录.
自定义了一个工具类UploadUtils.java
- 需要导入commons-fileupload-1.2.1.jar 和 commons-io-1.4.jar 这两个jar包
- UploadUtils.java工具类
package cn.itcast.store.utils;
import java.util.UUID;
public class UploadUtils {
/**
* 获取随机名称
* @param realName 真实名称
* @return uuid
*/
public static String getUUIDName(String realName){
//realname 可能是 1.jpg 也可能是 1
//获取后缀名
int index = realName.lastIndexOf(".");
if(index==-1){
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}else{
return UUIDUtils.getId()+realName.substring(index);
}
}
/**
* 获取文件真实名称
* @param name
* @return
*/
public static String getRealName(String name){
// c:/upload/1.jpg 1.jpg
//获取最后一个"/"
int index = name.lastIndexOf("\\");
return name.substring(index+1);
}
/**
* 获取文件目录
* @param name 文件名称
* @return 目录
*/
public static String getDir(String name){
//任意一个对象都有一个hash码 131313213
int i = name.hashCode();
//将hash码转成16禁止的字符串
String hex = Integer.toHexString(i);
System.out.println(hex);
int j=hex.length();
for(int k=0;k<8-j;k++){
hex="0"+hex;
}
return "/"+hex.charAt(0)+"/"+hex.charAt(1)+"/"+hex.charAt(2)+"/"+hex.charAt(3)+"/"+hex.charAt(4)+"/"+hex.charAt(5)+"/"+hex.charAt(6)+"/"+hex.charAt(7);
}
@SuppressWarnings("unused")
public static void main(String[] args) {
//String s="G:\\day17-基础加强\\resource\\1.jpg";
//String s="1.jgp";
//String realName = getRealName(s);
//System.out.println(realName);
//String uuidName = getUUIDName(realName);
//System.out.println(uuidName);
String dir = getDir("ASDFSADF");
// /b/b/5/6/3/b/a/1/ 234234.jpg
// /f/e/d/c/4/9/8/4/ 2341242314321.bmp
System.out.println(dir);
}
}
- 添加商品 addProduct()
//添加商品
public String addProduct(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1 获取前端提交过来的信息
DiskFileItemFactory factory = new DiskFileItemFactory();
FileUpload fileUpload = new FileUpload(factory);
//做的事情就是:通过 request.getInputStream() 获得数据,进行拆分,name对应的value封装到FielItem中
List<FileItem> list = fileUpload.parseRequest(request);
//2 遍历集合
Map<String,String> map = new HashMap<String,String>();
for (FileItem fileItem : list){
if(fileItem.isFormField()){
//3 是为普通项
//将数据保存在map集合中(在内存中)
//fileItem.getFieldName() 得到name属性的值
//fileItem.getString() 得到value属性的值
map.put(fileItem.getFieldName(),fileItem.getString("utf-8"));
}else {
//4 是上传项(上传图片)
//fileItem.getFieldName() 得到name属性的值
//fileItem.getName() 得到value属性的值
//fileItem.getString() 得到图片的(文件)内容 ,一般不使用这种方法获取,一般通过使用InputStream的方式获取
InputStream is = fileItem.getInputStream();
//获得原文件名
String oldName = fileItem.getName();
//根据原文件名获得 新的文件名
String uuidName = UploadUtils.getUUIDName(oldName);
System.out.println("新文件名:"+uuidName);
//创建存放的文件目录
//获得真实的路径
String realPath = getServletContext().getRealPath("products/3");
//System.out.println("真实路径:"+realPath);
//随机生成的一个8级目录 /f/e/d/c/4/9/8/4 (随机输入一个字符串,最好是文件名)
String dir = UploadUtils.getDir(uuidName);
// System.out.println("生成随机路径:"+dir);
String path = realPath + dir;
//System.out.println("全路径:"+path);
//在内存中声明一个目录
File newFile = new File(path);
if(!newFile.exists()){
//该目录不存在,在磁盘中创建该目录
//newFile.mkdir(); //建立单个目录
newFile.mkdirs(); //建立多个目录
}
//在内存中声明一个空文件
File file = new File(newFile, uuidName);
if (!file.exists()){
//该文件不存在,再磁盘中创建一个空文件
file.createNewFile();
}
//创建文件输出流,与该空文件联系起来
FileOutputStream os = new FileOutputStream(file);
//将数据写入到空文件中
IOUtils.copy(is,os);
//关闭流
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
//将属性name的值和属性value的值存到map中
map.put(fileItem.getFieldName(),"products/3"+dir+"/"+uuidName);
}
}
//5 利用BeanUtils将MAP中的数据填充到Product对象上
Product product = new Product();
BeanUtils.populate(product, map);
product.setPid(UUIDUtils.getId());
product.setPflag(0);
product.setPdate(new Date());
//调用service层,实现保存用户提交表单的信息
ProductService productService = new ProductServiceImpl();
productService.saveProduct(product);
//重定向到查询全部商品信息路径
return "AdminProductServlet?method=findAllProductsWithPage¤tPage=1";
}