1、 输出
<%
request.setAttribute("username","<h1>张三</h1>");
%>
<body>
${username }<!-- 会先在pageContext中找username,如果找不到去request -->
<c:out value="${username}"default="查无此人" escapeXml="true"></c:out>
</body>
通过EL表达式${username}这种可以获得输出,如果访问连接为:http://localhost:8080/JSTL/01/01.jsp?hello=world
那么可以通过EL表达式:${param.hello }获得传过来的参数值world
2、 分页工程测试
http://localhost:8080/Shop07-MVC01/user.do?method=list
(1)构造model类,主要是用于存放分页的各种数据,如总数、总页数、起始页、每页数等,有两个,一个Pager.java用于存放上面的数据,一个SystemContext.java用于线程操作,使得每个用户都会操作自己的页码
package com.lxp.model;
import java.util.List;
public class Pager<E> {
//第几页
private int pageIndex;
//每页显示多少条
private int pageSize;
//分页的开始值
private int pageOffset;
//总共多少条记录
private int totalRecord;
//总共多少页
private int totalPage;
//放置具体数据的列表
private List<E> datas;
public int getPageIndex() {
return pageIndex;
}
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getPageOffset() {
return pageOffset;
}
public void setPageOffset(int pageOffset) {
this.pageOffset = pageOffset;
}
public int getTotalRecord() {
return totalRecord;
}
public void setTotalRecord(int totalRecord) {
this.totalRecord = totalRecord;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<E> getDatas() {
return datas;
}
public void setDatas(List<E> datas) {
this.datas = datas;
}
}
package com.lxp.model;
//与分页有关
public class SystemContext {
private static ThreadLocal<Integer> pageSize = new ThreadLocal<Integer>();
private static ThreadLocal<Integer> pageIndex = new ThreadLocal<Integer>();
private static ThreadLocal<Integer> pageOffset = new ThreadLocal<Integer>();
private static ThreadLocal<String> order = new ThreadLocal<String>();//升序还是降序
private static ThreadLocal<String> sort = new ThreadLocal<String>();//根据哪一个字段来
public static int getPageSize() {
return pageSize.get();
}
public static void setPageSize(int _pageSize) {
pageSize.set(_pageSize);
}
public static void removePageSize() {
pageSize.remove();
}
public static int getPageIndex() {
return pageIndex.get();
}
public static void setPageIndex(int _pageIndex) {
pageIndex.set(_pageIndex);
}
public static void removePageIndex() {
pageIndex.remove();
}
public static int getPageOffset() {
return pageOffset.get();
}
public static void setPageOffset(int _pageOffset) {
pageOffset.set(_pageOffset);
}
public static void removePageOffset() {
pageOffset.remove();
}
public static String getOrder() {
return order.get();
}
public static void setOrder(String _order) {
order.set(_order);
}
public static void removeOrder() {
order.remove();
}
public static String getSort() {
return sort.get();
}
public static void setSort(String _sort) {
sort.set(_sort);
}
public static void removeSort() {
sort.remove();
}
}
(2)写dao层,将分页需要的数据要进行获取
public Pager<T> find(String sqlId,Map<String,Object>para) {
int pageSize = SystemContext.getPageSize();
int pageOffset = SystemContext.getPageOffset();
String order = SystemContext.getOrder();
String sort = SystemContext.getSort();
Pager<T> pages = new Pager<T>();
SqlSession session = null;
try {
session = MyBatisUtil.createSession();
if(para==null)
para = new HashMap<String, Object>();
para.put("pageSize", pageSize);
para.put("pageOffset", pageOffset);
para.put("order", order);
para.put("sort", sort);
List<T> datas = session.selectList(sqlId,para);
pages.setDatas(datas);
pages.setPageOffset(pageOffset);
pages.setPageSize(pageSize);
int totalRecord = session.selectOne(sqlId+"_count",para);//总数约定为查询一个+ _count
pages.setTotalRecord(totalRecord);
} finally {
MyBatisUtil.close(session);
}
return pages;
}
(3)相应的xml文件中的分页sql配置
<select id="find"resultType="User" parameterType="map">
<!-- 如果有多个查询条件,不好加逻辑,可以使用 select * from t_user where 1=1 然后
<if test="">and 条件1</if>
<if test="">and 条件2</if>
或者使用下面的<where>标签
-->
select * from t_user
<!-- <if test="name!=null">
where (username like '%${name}%' or nickname like'%${name}%')
</if>-->
<where>
<if test="name!=null">(username like'%${name}%' or nickname like '%${name}%')</if>
<if test="type!=null">and type=#{type}</if>
</where>
<if test="sort!=null">
order by ${sort}
<choose>
<when test="order!=null">${order}</when>
<otherwise>asc</otherwise>
</choose>
</if>
limit #{pageOffset},#{pageSize}
</select>
(4)写Filter类,用来对前端提交的请求进行分页预处理
package com.lxp.web;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.lxp.model.SystemContext;
public class SystemContextFilter implements Filter{
public void destroy() {}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException{
int pageOffset = 0;
int pageSize = 15;
String sort = req.getParameter("sort");
String order = req.getParameter("order");
try {
try {
if(req.getParameter("pager.offset")==null){
pageOffset=0;
} else
pageOffset = Integer.parseInt(req.getParameter("pager.offset"));
} catch(NumberFormatException e) {
e.printStackTrace();
}
SystemContext.setPageOffset(pageOffset);
SystemContext.setPageSize(pageSize);
SystemContext.setSort(sort);
SystemContext.setOrder(order);
chain.doFilter(req, resp);
} finally {
SystemContext.removePageOffset();
SystemContext.removePageSize();
SystemContext.removeSort();
SystemContext.removeOrder();
}
}
public void init(FilterConfig arg0) throws ServletException {}
}
(5)web.xml对filter进行声明
<filter>
<filter-name>SystemContextFilter</filter-name>
<filter-class>com.lxp.web.SystemContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SystemContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(6)导入pager-taglib.jar,主要是用于在jsp页面进行与分页相关的标签编写
(7)写pager.jsp页面,这个主要是用于分页配置,可以作为一个单独的页面动态include进去,所以单独写出来
<%@ page language="java"import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="pg"uri="http://jsptags.com/tags/navigation/pager"%>
<%@ taglib prefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<pg:pager maxPageItems="15"items="${param.items }" export="curPage=pageNumber"url="${param.url}">
<c:forEach items="${param.params}" var="p">
<pg:param name="${p}"/>
</c:forEach>
<pg:last>
共${param.items}记录,共${pageNumber }页,
</pg:last>
当前第${curPage }页
<pg:first>
<a href="${pageUrl }">首页</a>
</pg:first>
<pg:prev>
<a href="${pageUrl }">上一页</a>
</pg:prev>
<pg:pages>
<c:if test="${curPage eq pageNumber}">
[${pageNumber }]
</c:if>
<c:if test="${curPage ne pageNumber }">
<a href="${pageUrl }">${pageNumber }</a>
</c:if>
</pg:pages>
<pg:next>
<a href="${pageUrl }">下一页</a>
</pg:next>
<pg:last>
<a href="${pageUrl }">尾页</a>
</pg:last>
</pg:pager>
(8)在使用该pager.jsp的页面进行相应的参数配置,如table标签下的一个td中
<td colspan="6">
<jsp:include page="/inc/pager.jsp">
<jsp:param value="${users.totalRecord}"name="items"/>
<jsp:param value="user.do"name="url"/>
<jsp:param value="method,name"name="params"/>
</jsp:include>
</td>
3、BeanUtils使用方式:
(1)导入jar包
(2)创建一个Model类User
package com.lxp.model;
import java.util.Date;
public class User {
private int id;
private String username;
private int age;
private String password;
private Date born;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBorn() {
return born;
}
public void setBorn(Date born) {
this.born = born;
}
public String toString() {
return "User[age=" + age + ",born=" + born + ", id=" + id
+ ",password=" + password + ",username=" + username + "]";
}
}
(3)测试中只需要使用BeanUtils.copyProperty(new User(),”age”,1)这种形式就可以对User类的属性进行赋值
package com.lxp.test;
import java.util.Date;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.junit.Test;
import com.lxp.model.DateConverter;
import com.lxp.model.User;
public class Test01 {
@Test
public void test01() {
try {
User u = new User();
String value = "张三";
String key = "username";
BeanUtils.copyProperty(u, "age", 1);
BeanUtils.copyProperty(u, key, value);
User u2 = new User();
BeanUtils.copyProperties(u2, u);
//BeanUtils无法自动拷贝日期,因为日期的格式太多,所以不知道该转换
//成何种形式,就需要自己定义相应的转换器来完成转换
/*
* 定义转换器步骤
* 1、创建一个类让其实现Converter接口
* 2、覆盖这个接口中的convert方法,该方法中实现转换
* 3、在时下拷贝之前注册转换器
*/
ConvertUtils.register(new DateConverter(), Date.class);
BeanUtils.copyProperty(u, "born","1923-12-23");
System.out.println(u.getBorn());
System.out.println(u2);
} catch (Exception e) {
}
}
}
(4)对于特殊的情况,当User中有Date类型时,BeanUtils是不知道该如何进行转换的,因为日期的类型很多,这个时候就需要自己手动写个转换器类,该类需要实现Converter接口
package com.lxp.model;
import java.util.Date;
import java.text.SimpleDateFormat;
import org.apache.commons.beanutils.Converter;
public class DateConverter implements Converter{
/*
* 该方法两个参数,第一个参数表示转换的类型,如果要拷贝一个字符串到日期中,此时
* 就是日期类型,第二个参数表示转换的值
*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@Override
public <T> T convert(Class<T> clz, Object value) {
if(clz!=Date.class) {
return null;
}
try {
if (value instanceof String) {
return (T) sdf.parse((String) value);
}
} catch (Exception e) {
}
return null;
}
}
(5)调用方式如上面的(3)所示,对User相应的Date属性进行赋值之前,需要先进行注册即可ConvertUtils.register(new DateConverter(), Date.class);
注意:如果要实现这种方式:
(1)有一个Point的Model类
package com.lxp.model;
public class Point {
int x;
int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
(2)User类中有这个Point的引用
private Point point;
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
(3)如果想通过输入“12,13”这种方式就能够给User类中的Point进行x和y赋值的话,如下所示,需要写一个转换类BeanUtils.copyProperty(u,"point", "12,13");
package com.lxp.model;
import java.util.Date;
importjava.text.SimpleDateFormat;
importorg.apache.commons.beanutils.Converter;
public class PointConverterimplements Converter{
public <T> T convert(Class<T> clz, Object value) {
if(clz!=Point.class) {
return null;
}
try {
if (value instanceof String) {
String value2 = (String) value;
String[] params = value2.split(",");
Point p = new Point();
p.setX(Integer.parseInt(params[0]));
p.setY(Integer.parseInt(params[1]));
return (T) p;
}
} catch (Exception e) {
}
return null;
}
}
4、文件上传(使用commons-fileupload.jar以及commons-io.jar这两个jar文件)
(1)普通的实现方式:
①有ServletFileUpload获得是否是Multipart形式提交,如果是,执行②
②创建一个ServletFileUpload对象upload。
③由上面的upload创建一个FileItemIterator对象
④获取iterator值,获取FileItemStram对象fis,并通过这个对象通过openStream()方法获得InputStrame对象
⑤使用fis判断是否是表单,如果是表单的话就直接获取表单中的参数和值就可以了,这里通过Streams.asString(is)来获得表单的值。如果不是表单说明是文件上传,可以通过FileOutputStream来进行byte写入。
public voiddoPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException {
file02(request,response);
request.setCharacterEncoding("utf-8");
boolean isMultipart =ServletFileUpload.isMultipartContent(request);
InputStream is = null;
FileOutputStream fos = null;
try {
if (isMultipart) {
ServletFileUpload upload = newServletFileUpload();
FileItemIterator iter =upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream fis =iter.next();
//是multipart就表示需要使用字节数据进行传递,需要使用输入流
is = fis.openStream();
if (fis.isFormField()) {
System.out.println(fis.getFieldName());
System.out.println(newString(Streams.asString(is).getBytes("ISO-8859-1"),"gbk"));//通过该方法可以将流中的数据转换为String
} else {
System.out.println(fis.getName());
String path =request.getSession().getServletContext().getRealPath("/upload");
path = path + "/"+ fis.getName();
fos = newFileOutputStream(path);
byte[] buf = newbyte[2014];
int len = 0;
while((len=is.read(buf))>0){
fos.write(buf,0,len);
}
}
}
}
} catch (Exception e) {
} finally {
if(is!=null) is.close();
if(fos!=null) fos.close();
}
}
(2)使用自己创建的一个新类来创建一个封装,然后servlet直接简单调用就好了,这个类需要继承HttpServletRequestWrapper。将表单提交上来的数据如果是以Multipart形式提交的,首先创建MultipartRequestWrapper对象,然后将提交上来的数据封装在Map中,servlet直接调用这里面的相应的getParameter方法即可获得,以前通过req.getParameter()方法获得的值,从而达到统一。另外,这里文件上传是通过Streams.copy(is, new FileOutputStream(PATH + "/upload/" + fis.getName()), true);这个方法来获得的,不是上面的byte形式,比较简单。
注意:在IE中,传过来的fis.getName就是c:/……这种全路径,那么可以使用
//对于IE上传的文件会得到完整的绝对路径,需要将绝对路径字符串进行截取文件名
String fname = FilenameUtils.getName(fis.getName());//得到文件名
这个方法可以实现兼容,就可以直接获得文件名,而不用管IE还是火狐
public class MultipartRequestWrapper extends HttpServletRequestWrapper{
private Map<String,String[]>params = new HashMap<String, String[]>();
private static final String PATH = "D:\\MyEclipse-8.6\\Workspaces\\MyEclipse8.6\\FileUploadTest01\\WebRoot\\";
public MultipartRequestWrapper(HttpServletRequest request) {
super(request);
setParams(request);
}
private void setParams(HttpServletRequest request) {
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generatedcatch block
e1.printStackTrace();
}
//判断是否是multipart类型
boolean isMul = ServletFileUpload.isMultipartContent(request);
if(isMul) {
ServletFileUpload upload = new ServletFileUpload();
try {
FileItemIterator iter =upload.getItemIterator(request);
InputStream is = null;
while (iter.hasNext()) {
FileItemStream fis = iter.next();
is = fis.openStream();
if (fis.isFormField()) {
setFormParams(fis.getFieldName(),is);//主要是针对类似于checkbox这种多name的
} else {
//要输入流中有数据(>0)才进上传,否则不进行
if(is.available()>0) {
//对于IE上传的文件会得到完整的绝对路径,需要将绝对路径字符串进行截取文件名
String fname = FilenameUtils.getName(fis.getName());//得到文件名
//完成文件上传
System.out.println(PATH+"upload\\"+ fname);
Streams.copy(is, new FileOutputStream(PATH + "/upload/"
+ fname), true);
params.put(fis.getFieldName(), new String[] { fis
.getName() });
}
}
}
} catch (Exception e) {
// TODO: handleexception
}
} else {
//如果不是Multipart直接通过请求获取值
params = request.getParameterMap();
}
}
private void setFormParams(String paramKey,InputStream is) throws IOException {
if(params.containsKey(paramKey)) {
//说明表单域中已经存在了值,需要向params的String的数组中添加
String[] values = params.get(paramKey);
values = Arrays.copyOf(values, values.length+1);//数组长度加1
values[values.length-1] = Streams.asString(is);
params.put(paramKey, values);
} else {
params.put(paramKey, new String[]{Streams.asString(is)});
}
}
public Map<String,String[]> getParameterMap() {
return params;
}
public String getParameter(String name) {
String[] values = params.get(name);
if(values!=null) {
return values[0];
}
return null;
}
@Override
public String[] getParameterValues(String name) {
String[] values = params.get(name);
if(values!=null) {
return values;
}
return null;
}
}