Structs2是在webwork2基础上发展而来的。
Structs是基于MVC的框架
因为我们对MVC的理解不同,可能造成不同公司写程序的时候,规范不统一,这样不利于程序的维护和扩展,所有我们有必要用一个统一的规范来开发项目。
Struts的好处
① 程序更加规范化
② 程序开发的开发 效率提高了
③ 程序的可读性增加
④ 程序的可维护性增加了
Strus的不足之处
① form表单有点鸡肋
② action是单态(对网站并发性的处理有影响)就是始终是一个action,不管多少人访问
单态是指在整个程序运行的过程中,始终是一个对象为你服务
Struts开发流程
① 在开发struts的时候,需要struts开发包
② 先写出login.jsp
③ 编写ActionForm和Action
④ 配置struts-config.xml文件,一般放在WEB-INF目录下(不是必须)
⑤ 写出welcome.jsp和error.jsp页面
⑥ 在wel.xml中配 置ActionServlet
⑦ 开始使用我们的struts
⑧ Struts中文乱码问题—过滤器
定义表单类
定义属性:我们定义属性名字的时候,应该和jsp页面的控件名称一样。
但是可以不一样,只要保证set和get方法和属性名存在关联
struts-config.xml
Ation里面还有一个scope属性可以选择两个值request,session默认是session
Scope=”request” 表示该action对象的表单对象的生命周期是request的,request=request.setAttribute(“userForm”,userForm);
Scope=”session” 表示该action对象的表单对象的生命周期是session的,session=request.getSession().setAttribute(“userForm”,userForm);
第一个userForm表示表单对象名,第二个userForm表示表单对象实例,
可以通过下面的方法来取出我们存放的userForm对象实例 <%=((UserForm)request.getAttribute(“userForm”)).getUsername() %>
Web.xml配置
使用过滤器配合STRUTS解决中文乱码问题
在提交给ActionServlet之前设置一个过滤器 并设置
Request.setCharacterEncoding(“utf-8”);
过滤器继承的接口是在javax.servlet.Filter;下面的
一个过滤器:代码如下
package myfilters;
import java.io.IOException;
import java.io.PrintWriter;
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 javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Myfilter extends HttpServlet implements Filter {
private String encoding;
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
arg0.setCharacterEncoding(encoding); //设置编码方式
arg2.doFilter(arg0, arg1);
arg1.setContentType("text/html;charset=utf-8");
}
public void init(FilterConfig arg0) throws ServletException {
encoding=arg0.getInitParameter(“encoding”); // 在这里获取到配置文件的内容
}
}
配置过滤器的web.xml
<filter>
<filter-name>Myfilter</filter-name>
<filter-class>myfilters.Myfilter</filter-class>
<init-param>
<param-name>encoding</param-name> //设置编码方式
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping> //过滤器的映射
<filter-name>Myfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在一个项目中可以有多个struts可以有多个配置文件
配置的时候只需要在后面继续写上就行/WEB-INF/struts-config2.xml
<param-value>/WEB-INF/struts-config.xml,</param-value>
使用工具来开发struts
① 用工具引入sturts包和配置文件,然后自己配置struts-config.xml完成开发
② 完全依赖myeclipse提供的工具完成struts开发
第一种方式
开发步骤:
① 建立web工程
② Myeclipse>>add Struts Capabilities
③
④ 开发login.jsp
⑤ 开发action和actionform
⑥ 配置Struts-config
第二种方法
① 创建一个web工程
② 引入Sturts开发包
③ 开发login.jsp
④ 开发action和actionform
⑤ 编写ok和err页面
⑥ 拖拽进Struts-config
⑦ 在action中添加你的业务逻辑
运行原理图:
Jstl标签技术>>jsp标准标签库
Jstl标签的好处
① 在应用程序服务器之间提供统一的接口,从而提供了web应用在不同服务器的移植
② 简化jsp与web应用程序的开发
③ 减少jsp中java片段的代码,可以达到在jsp页面中没有任何java代码,代码更加简洁
④ 提高jsp的开发速度,缩短开发周期。
普通标签:
<c:out>
用于把计算的结果输出到jspwriter对象
使用标签
① 引入我们的标签库
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core”%>
例如:
<c:out value=”helloworld”></c:cout>
上面一句代码将会在html界面输入helloword
Request.setAttribute(“abc”,”你好”)
<c:out value=”${abc}”/> == request.getAttribute(“abc”).toString();
如果我们的域对象中有相同的属性名c:out的优先级是
Pagecontext>request>session>application
<c:out value=”${abc}”default=”没有值”>
如果找不到abc对应的值就输出没有值
一个案例:
Request.setAttribute(“abc”,”
你好<a href=”http://www.sohu.com”>sohu</a>”)
<c:out value=”${abc}” default=”没有值” escapeXml=”false”>
这样就好输出一个超链接sohu ,但是如果没有加escapexml那么就会以文本的方式输出request对象里面的内容就不会出现超链接
输出对象的值
放入
User u=new User();
u.setName(“小猫”);
u.setAge(30);
request.setAttribute(“user1”,u);
取出
取出名字<c:out value=”${user1.name}”></c:out>
还可以直接这样写 ${user1.name} //el表达式
<c:set>标签
<c:set var=”abc” value=”中国,北京” scope=”request”/>
上面的标签等价 request.setAttribute(“abc”,”中国,北京”);
输出
<c:out value=”${abc}”/>
<c:remove>
这个标签用于删除某个变量或是属性
一个例子
Request.setAttribute(“a”,”你好”);
<c:remove var=”a”/>
删除掉a这个变量
<c:catch>
这个标签用于捕获嵌套在它内部的标签抛出的异常
一个案例:
<c:catch var=”myexception”>
<% int i=8/0;%>
</c:catch>
<c:out value=”${myexception}”></c:out>
将会输出错误信息
条件标签:
<c:if>
用于进行条件的判断,如果它的test属性为true,那么他就会去处理body里面的内容
Request.setAttribute(“a”,”hello”);
<c:if test=”${a==’hello’}”>ok</c:if>
注意hello要写在单引号里面
<c:choose>用于条件的选择它和<c:when>,<c:otherwise>一起使用
<c:when>它代表了<c:choose>的一个条件分支,使用它的限制条件:
① 必须以<c:choose>作为它的父标签
② 必须在<c:otherwise>之前出现
<c:otherwise>它代表了<c:choose>的最后一个分支,使用它的限制条件
① 必须以<c:choose>作为它的父标签
② 必须是<c:choose>的最后分支出现
例如:
<c :choose>
<c:when></c:when>
<c:when></c:when>
<c:otherwise></c:otherwise>
</c:choose>
迭代标签
<c:foreach>
用来替代for循环的
例如
Request.setAttribute(“allrate”,a1);
注意a1是一个ArrayList的集合
<c:forEach items=”${allrats}” var=”rat”>
//rat代表的是集合里的取出来的对象
<c:out value=”${rat.name}”/> //输出对象的名字
<c:out value=”${rat.age}”/> //输出对象的年龄
</c:forEach>
固定循环次数
第一种
<c:forEach var=”i” begin=”1” end=”10”>
<c:out value=”${i}”/>
</c:forEach>
输出i的值从1到10
第二种
<c:forEach var=”i” begin=”1” end=”10” step=”3”>
<c:out value=”${i}”/>
</c:forEach>
其中step代表步长,第一次输出i=1的值,第二次输出i=4的值以此类推
<c:fortokens>的使用,用来分隔字符的
<c:forTokens items=”12;45;你好;ddd” delims=”;” var=”temp”>
${temp}
</c:forTokens>
上面的代码会输出12 45 你好 ddd
Request.setAttribute(“abc”,”abc;12;23;你好;uuu”);
<c:forTokens items=”${abc}” delims=”;” var=”temp”>
这样也会输出request里面的字符串的
${temp}</c:forTokens>
Js里面的页面跳转
Window.location.href=”/项目名/servlet名?pageNow=”+pageNow
把上面的代码写在js里面也可以实现跳转
Jstl细节问题
① 迭代的对象是HASHMAP或者是HASHSET
<%
Map map=new HashMap();
Map.put(“aa”,”宝玉”);
Map.put(“bb”,”黛玉”);
//把map放入某个域对象session,request,pageContext,application
Request.setAttribute(“persons”,map);
%>
<c:forEach items=”${persons}” var=”per”>
Key=${per.key} //取出key值
Value=${per.value} //取出value的值
</c:forEach>
如果存放的是对象,则需要per.value.name
就是后面再加一个点然后写上属性名
用<c:if>
对是否为空进行判断
Empty属性:用来对一个空变量值进行判断:null,一个空String,空数字,空Map,没有条目的Collection
例如判断集合是否为空:
<c:if test=”${empty myrats}”> //判断为空
<c:if test=”${!empty myrats}”>//判断不为空
//myrats为一个集合
重定向标签
<c:redirect url=”www.baidu.com”></c:redirect>
引入标签
<c:import url=”a.jsp”></c:import>
url=”a.jsp”会引入a.jsp的内容
<c:param name=”name” value=”shunping”/>
在下一个页面可以直接用${param.name}就可以获得value的值
下面的代码也可以
<a href=”bb.jsp?id=12”>点击</a>点击就可以跳到bb.jsp
在bb.jsp里面写下面内容就可以获得Id值
${param.id}
Struts标签
在javaee规范中有三种标签
① 自定义标签
② Jstl标签
③ Struts标签
Jstl标签实际上可以完成标签的任务。
当struts设计者在提供struts框架后同时提供了一套标签库。把它命名为struts标签,在实际开发中jstl标签可以和struts标签混合使用。
Html标签
该标签库包含的标签可以用来创建Struts输入表单和用户界面
相当于封装了html标签,主要是为了和struts框架统一,所以做的封装。
引入struts的html标签
先引入struts框架>>struts-taglib包里面有一个struts.taglib.html
在meta-inf里面有一个struts-html.tld(标签描述文件)找到uri
引入标签代码
<%@ taglib uri=http://struts.apache.org/tags-html prefix=”html”%>
一个例子定义一个按钮:
<html:button property=”mybutton” value=”提交”></html:button>
其中property属性就是button的name
<html:base>的使用
<html:base ref=”http://www.sohu.com”>
<a href=”#”>goto</a>
加入没有设置超链接里面的href连接地址就会自动调用base里面的地址跳转到base里面的地址。
<html:image> ==<input type=”image”> 图片按钮
<html:img> ==<img> 显示一个图片
超链接
<html:link href=”http://www.baidu.com”>连接到百度</html:link>
<html:form>
在html标签库中form标签是最重要的标签,它和struts框架紧密结合,form标签和一个actionform对应,当form的各个字段与actionform的属性匹配时,那么当客户端把form提交后,struts框架将保存用户的输入到对应的actionform中,这样就完成了标签与组件的交互工作。
Struts的html标签如果涉及到输入信息,struts框架要求和一个表单类对应,而且应放到一个<html:form>
中
例如:
<html:form action=”/login.do” method=”post”>
<html:text property=”name”></html:text>
</html:form>
这里应该建立一个表单类并且定义一个变量name而且要有它的set和get方法
这样才能使用表单
Split()的用法
该方法在java.lang.String 包下
将一个字符串分割为子字符串,然后将结果作为字符串数组返回。
例如:
Request.setAttribute(“words”,”花花;拜拜;露露”);
String keywords[];
keywords=arg0.getInitParameter(“words”).split(“;”);
这是keywords里面就是存放的花花,拜拜,露露,并且大小是3
Bean标签库
Bean标签库为访问bean和它的属性提供了方便的机制:
1. 该标签库包含的标签可以用来创建bean,访问bean,和访问bean的属性
2. 提供了依据cookies,headers和parameters的值创建相关bean的能力
使用的时候也需要先导入bean标签库
和导入html标签一样。
<bean:write>
标签
用于输出信息
例如:
<%Request.setAttribute(“abc”,”hello,world”);%>
<bean:write name=”abc”>
这样就会自动输出hello,world
也可以在里面设置scope=“request”来设置域空间,也可以不指定,它会自动查找
取出对象的属性
<% Cat cat=new Cat();
Cat.setName(“小猫”);
Cat.setAge(30);
Request.setAttribute(“cat1”,cat);
%>
<bean:write name=”cat1” property=”name”/>
这样就会输出cat1的名字,同样property=name指的是getname方法
上面的代码中Cat的一个实例,是一个domain对象,同时也是一个javabean
其中javabean的属 性值得是get和set方法并不是那个属性变量
Bean:message标签
该标签通常和资源文件配置使用,可以更加方便的输出信息,在资源文件中配置就行,就是我们自动生成那个包里面的文件,其中#代表注释。
<bean:message key=”key1” arg0=”jone”/>
其中需要现在配置文件中写一个:
Key1=你要写的内容 {你的arg0里面的内容}
在jsp标签中定义一个bean
<bean:define id=”kkk” name=”abc” value=”hello” scope=”request” />
相当于在request域中放入一个abc的对象,值为hello,取出的时候可以用id,或者用name也可以。
下面一个案例:
上面的代码和下面的代码是到等价的
<logic>
标签 相当于我们的那个c:for each标签
Logic标签库主要用于管理和条件相关的输出,对某些对象进行迭代输出,和流程管理。
同样需要引入标签库,引入方法同html
一个案例:
定义三个cat实例 然后加入到arraylist集合对象a1中
Request.setAttribute(“cats”,a1);
<logic:iterate id=”mycat” name=”cats”>
//id 相当于cats.get(i)进行迭代取出每个存入的对象。
${mycat.name} //输出猫的名字
${mycat.age} //输出猫的年龄
</logic:iterate>
<logic:empty>标签 判断是否为空
<logic:empty name=”ee”>
Ee不存在
</logic:empty>
首先它回去到域空间里面查找是否有个叫ee的对象,如果没有个找到就会返回空
<logic notEmpty name=”cats>
Cats属性存在
</logic:notEmpty>
如果cats存在就会返回里面的值
用logic判断大小
<logic:iterate id=”mycat” name=”cats”>
<logic:greaterThan name=”mycat” value=”20” property=”age”>
年龄大于20岁</logic:greaterThan>
</logic:iterate>
小猫的age会和property里面的值进行比对,如果大于20就会输出里面的内容
DispatchAction 分派action
程序设计时,设计多个action会造成程序显得比较臃肿,可以把一类请求写到一个action中处理,这样程序变得简洁,利于维护和扩展。
建立我们自己的action时候要继承dispatchaction
在struts-config.xml中配置
在我们建立的action中需要重写方法
清空session,把session里面的属性全部清空掉
Request.getSession().invalidate();
清除session里面一个属性
Request.getSession().removeAttribute(“属性名”);
如果一个forward写在action的标签中,则说明是局部跳转。
例如:
<forward name=”loginok” path=”ok.jsp”>
<forward name=”gologin” path=”login.jsp”>
全局跳转:
在struts-config.xml里面配置
<global-forwards>
<forward name=”goerr” path=”/WEB-INF/err.jsp”/>
</global-forwards>
所谓全局跳转指的是所有的action都可以跳转到该页面,所谓局部跳转指的是只有本action可以跳转到该页面
一个例子:所有的action都可以通过goerr来跳转到err.jsp
但是test action就不可以通过gologin跳转到login.jsp因为他是局部的
Dynamic Form动态表单
为什么需要动态表单:
当我们表单类的属性个数和类型不能确定的时候,我们可以使用动态表单来解决问题
动态表单和普通表单类的区别在:
1. 普通表单类actionform是首先你需要定义一个类,然后配置到struts中
2. 动态表单完全依赖反射机制创建,因此不需要去建一个一个这样的类,直接在struts-config中配置即可。
在struts-config中配置动态表单:
其中name,password,email,就是表单中的名字,例如
<input type=”text” name=”name”/>
<input type=”password” name=”password”/>
在action中取出动态表单属性
文件上传和下载
原理图:
一个action是否必须要配置一个表单呢,不一定
一个action是否可以配置多个表单,不可以。
如果我们的表单有文件(file)控件,则需要重新指定表单的编码方式。
<form enctype=”multipart/form-data”></form>
得到发布的项目上传到tomcat服务器后的绝对路径
File=This.getServlet().getServletContext().getRealPath(“/file”);
InputStream()的read方法
Read(b)
Byte b[]=new Byte[1024];
从输入流中读取一定数量的字节,并将其存储在缓冲区数组B中。
会返回一个int,int代表读入缓冲区的总字节数,如果因为已经到达末尾而不再有数据可用,则返回-1.
文件上传时在form表单中需要这样写
photo:<input type="file" name="userphoto"/><br/>
在userform表单类中需要这样写
private FormFile userphoto;
在action中得到上传的文件
Formfile formfile=userForm.getUserphoto();
获取文件的输入流
InputStream is=formfile.getInputStreanm();
一个案例:读入文件和向指定的目录写入文件
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
UserForm userForm = (UserForm) form;// TODO Auto-generated method stub
FormFile formfile=userForm.getUserphoto();
String filename=formfile.getFileName();
float size=formfile.getFileSize();
String filepath=this.getServlet().getServletContext().getRealPath("images");
System.out.println(filepath);
InputStream is=null;
OutputStream os=null;
try {
//读取字节文件
is=formfile.getInputStream();
//把字节文件写入指定的目录
os=new FileOutputStream(filepath+"\\"+filename);
int len=0;
//定义一个每次读取字节流大小的数组
byte[] bytes=new byte[1024];
//循环处理读入字节流
while((len=is.read(bytes))>0){
//读一点,写一点
os.write(bytes, 0, len);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally{
try {
os.close();
is.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
return mapping.findForward("ok");
}
解决文件上传的细节问题:
1. 文件名相同覆盖文件问题。
我们使用一个产生随机的十六进制数的工具UUID
String uuid=UUID.randomUUID().toString();
上面代码就会产生一个随机的16进制数:例如
df3dbbe9-5d49-4d91-9423-bba671cf61dc
substring(2,5)
从字符串的第二个字符开始截取到第四个字符
String.lastIndexOf(string a)
返回指定子字符串在此字符串中最右边出现处的索引
给我们上传的文件重新命名:
String uuid=UUID.randomUUID().toString();
String s=”abcsdsdf.jpg”;
int beginindex=s.lastIndexOf(“.”);
String newfilename=uuid+s.substring(beginindex,s.length());
解决上传文件名是中文的问题
1.我们像以前那样配置一个过滤器。
文件下载