eclipse学习(第二章:初识ssh)——17.Struts2注释
- 前言
- 使用到的注解说明
- 项目搭建
- 关于注解位置的部分说明
- 中途遇到的异常
- 1、HTTP Status 404 - There is no Action mapped for namespace [/] and action name [loginValidator] associated with context path [/ssh_learn_annotation].
- 2、No configuration found for the specified action: '/user/actionA' in namespace: ''. Form action defaulting to 'action' attribute's literal value.
- 3、拦截器与表单数据校验冲突导致无法进行校验
- 项目地址
- 扩展——更多的注释说明
前言
本文是参考自以下的网站后自己实践后写的一些笔记
https://www.w3cschool.cn/struts_2/struts_annotations.html
使用到的注解说明
@ParentPackage,这个注解对应了xml文件中的package节点,它只有一个属性叫value,其实就是package的name属性;
@Namespace,命名空间,也就是xml文件中<package>的namespace属性;
@Action,这个注解对应<action>节点。这个注解可以应用于action类上,也可以应用于方法上。这个注解中有几个属性:
value(),表示action的URL,也就是<action>节点中的name属性;
results(),表示action的多个result;这个属性是一个数组属性,因此可以定义多个Result;
interceptorRefs(),表示action的多个拦截器。这个属性也是一个数组属性,因此可以定义多个拦截器;
params(),这是一个String类型的数组,它按照name/value的形式组织,是传给action的参数;
exceptionMappings(),这是异常属性,它是一个ExceptionMapping的数组属性,表示action的异常,在使用时必须引用相应的拦截器;
@Result,这个注解对应了<result>节点。这个注解只能应用于action类上。这个注解中也有几个属性:
name(),表示action方法的返回值,也就是<result>节点的name属性,默认情况下是【success】;
location(),表示view层文件的位置,可以是相对路径,也可以是绝对路径;
type(),是action的类型,比如redirect;
dispatcher:它代表的是请求转发,也是默认值。它一般用于从action跳转到页面。
chain:它也相当于请求转发。它一般情况下用于从一个action跳转到另一个action。
redirect:它代表的是重定向 它一般用于从action跳转到页面
redirectAction: 它代表的是重定向 它一般用于从action跳转另一个action。
stream:代表的是服务器端返回的是一个流,一般用于下载。
freemarker(了解即可): 一种模板技术,通过以流向模板页面输入数据,而得到我们想要的页面
params(),是一个String数组。也是以name/value形式传送给result的参数;
项目搭建
1、初始化项目及jar包拉取
使用注解开发需要使用到的相关jar包,其中最重要的是struts2-convention-plugin,这个是使用注解的最重要的包
2、修改web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ssh_learn_annotation</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
<init-param>
<param-name>struts.devMode</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3、创建PlayAction
该文件必须放在指定文件夹内,详细可以去看下面那个中途出现的异常。
package com.czx.annotation.action;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.ExceptionMapping;
import org.apache.struts2.convention.annotation.ExceptionMappings;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.validator.annotations.IntRangeFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;
@ParentPackage(value = "struts-default")
//命名空间,也可说是在访问路径中加入的内容
@Namespace(value = "/user")
//全局定义action
//@Actions({
// @Action(value = "actionA",results = {
// @Result(name = "success",location = "/success.jsp"),
// @Result(name = "error",location = "/error.jsp")
// }),
// @Action(value="actionB",results = {
// @Result(name = "success",location = "/success.jsp"),
// @Result(name = "error",location = "/error.jsp")
// })
//})
//全局定义result
//@Results({
// @Result(name = "success",location = "/success.jsp"),
// @Result(name = "input",location = "/index.jsp")
//})
public class PlayAction extends ActionSupport {
public String getName() {
return name;
}
@RequiredStringValidator(message = "名称不能为空")
public void setName(String name) {
this.name = name;
}
@RequiredFieldValidator(message = "年龄不能为空")
@IntRangeFieldValidator(message = "年龄必须在18-60岁之间",max = "60",min = "18")
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
private String name;
private Integer age;
@Action(//访问路径
value="actionA",
//返回结果集处理器
results = {
@Result(name = "success",location = "/success.jsp",type = "dispatcher"),
@Result(name = "input",location = "/index.jsp",type = "dispatcher")
},
//拦截器
interceptorRefs = {
@InterceptorRef(value = "defaultStack"),
// @InterceptorRef(value = "params"),
// @InterceptorRef(value = "validation"),
@InterceptorRef(value = "timer")
},
//出现异常怎么处理
exceptionMappings = {
@ExceptionMapping(exception = "java.null.Exception",result = "error.jsp"),
@ExceptionMapping(exception = " java.lang.ArrayIndexOutOfBoundsException",result = "error.jsp")
}
)
public String login() {
System.out.println(name+":"+age);
return "success";
}
}
4、创建前端页面
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:form action="actionA" method="post" namespace="/user">
<s:textfield name="name" label="名称" size="20"></s:textfield>
<s:textfield name="age" label="年龄" size="20"></s:textfield>
<s:submit value="提交" align="center"></s:submit>
</s:form>
</body>
</html>
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
成功返回获得的内容
</body>
</html>
error.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
获取内容失败
</body>
</html>
5、测试
访问http://localhost:8080/ssh_learn_annotation/
直接点击提交是这样的
输入名称且年龄在18-60之间再点击提交,就访问成功了
关于注解位置的部分说明
action可以在类上面写也可以在方法上面写,如果在一个类中,类上面写了,方法也写了。action名称一致但是目的地不一致,这个时候跳转的会选择类上面的那个。
action里面可以写result,如果result写在类上面,方法上面有action且action内部带有result,以方法上面那个action为准。
如果在类上面定义了result和action且action内有定义result,那么以action内的为准。
经过这个测试,可以得知同样的内容,以类上面的为优先。如果是action里面的内容的话,不管它位置以action的为准。
中途遇到的异常
1、HTTP Status 404 - There is no Action mapped for namespace [/] and action name [loginValidator] associated with context path [/ssh_learn_annotation].
这里很麻烦,因为我看是可以不写struts.xml内部的action来实现注解开发的,struts.xml一般是配置struts环境配置。但是这个问题似乎又跟不写struts.xml有关,所以很麻烦。这个问题的意思是找不到对应的action。
所以说这里需要进行包扫描,那么框架本身应该是存在默认的规则的,你找到了规则那么就能解决这个问题。当然你也可以自己写struts.xml自己定义位置。我这里是通过将目标action类移至action文件夹下解决的。
规则如下
1、Struts 2 Annotation概念
Struts 2注解是由Struts 2 convention plugin所支持的。因此,我们必须理解“扫描方式”和“命名转换”机制背后的东西。
1.1 Struts 2对注解的扫描顺序
Struts 2 只扫描名为struts、struts2、action或actions的特定目录。 扫描的工作顺序如下:
- 先扫描位于名为“struts、struts2、action或actions”的包中的注解类;
- 接下来,扫描匹配如下条件的文件:
- 实现com.opensymphony.xwork2.Action接口;
- 继承自com.opensymphony.xwork2.ActionSupport类;
- 文件名以Action结尾(比如UserAction、LoginAction)
1.2 命名转换
Struts 2 convention插件将所有的注解action文件名称转换为特定的格式。 例如:LoginAction.java
- 首先,移除文件名末尾的”Action”单词,如果存在的话;
- 接下来,将文件名的第一个字母转换为小写。
这样,在移除末尾的action和转换第一个字母的大小写以后,LoginAction.action将转变为login.action。(不完全是这样,例如BasicTestAction 则使用 basic-test 访问)
Struts 2 convention插件的“扫描算法”和“命名转换”特性带来了很多便利和好处,不过这要求在我们的Struts 2项目中必须正确地遵循命名约定。否则,这将会造成极大的麻烦。
2、No configuration found for the specified action: ‘/user/actionA’ in namespace: ‘’. Form action defaulting to ‘action’ attribute’s literal value.
不应该直接在前端页面的表单中的action内加入namespace的内容,而是要分开两个属性。
<s:form action="/user/actionA" method="post">
变为
<s:form action="actionA" method="post" namespace="/user">
3、拦截器与表单数据校验冲突导致无法进行校验
解决办法:因为自己设置的拦截器并不完全。你可能只是简单地调用了一个timer或者其他的拦截器,但是一般会调用这个defaultStack拦截堆栈。以下是从struts-default.xml文件中选取的截图显示,看看里面包含了什么,里面有一个很关键validation,这个是做数据检验的,开了才行,不开就不行哦
项目地址
这个仓库里面的ssh_learn_annotation
https://gitee.com/mrchen13427566118/ssh_learn.git
如果不会怎么弄到eclipse的话,就看这里
https://blog.csdn.net/weixin_43987277/article/details/116936221
扩展——更多的注释说明
Namespace注释(Action注释)
@Namespace注释允许在Action类中定义Action的命名空间,而不是基于零配置的约定。
@Namespace("/content")
public class Employee extends ActionSupport{
...
}
Result注释(Action注释)
@Result注释允许在Action类中定义Action的结果,而不是XML文件。
@Result(name="success", value="/success.jsp")
public class Employee extends ActionSupport{
...
}
Results注释(Action注释)
@Results注释定义了一个Action的一组结果。
@Results({
@Result(name="success", value="/success.jsp"),
@Result(name="error", value="/error.jsp")
})
public class Employee extends ActionSupport{
...
}
After注释(拦截器注释)
@After注释标记需要在执行主action方法和结果后调用的action方法(忽略返回值)。
public class Employee extends ActionSupport{
@After
public void isValid() throws ValidationException {
// validate model object, throw exception if failed
}
public String execute() {
// perform secure action
return SUCCESS;
}
}
Before注释(拦截器注释)
@Before注释标记需要在执行主action方法和结果之前调用的action方法(忽略返回值)。
public class Employee extends ActionSupport{
@Before
public void isAuthorized() throws AuthenticationException {
// authorize request, throw exception if failed
}
public String execute() {
// perform secure action
return SUCCESS;
}
}
BeforeResult注释(拦截器注释)
@BeforeResult注释标记需要在结果之前执行的action方法(忽略返回值)。
public class Employee extends ActionSupport{
@BeforeResult
public void isValid() throws ValidationException {
// validate model object, throw exception if failed
}
public String execute() {
// perform action
return SUCCESS;
}
}
ConversionErrorFieldValidator注释(验证注释)
此验证注释检查字段是否存在任何转换错误,并在存在时应用。
public class Employee extends ActionSupport{
@ConversionErrorFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getName() {
return name;
}
}
DateRangeFieldValidator注释(验证注释)
此验证注释检查日期字段的值是否在指定范围内。
public class Employee extends ActionSupport{
@DateRangeFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
min = "2005/01/01", max = "2005/12/31")
public String getDOB() {
return dob;
}
}
DoubleRangeFieldValidator注释(验证注释)
此验证注释检查具有指定范围内值的双字段。如果既不设置min也不设置max,则不会执行任何操作。
public class Employee extends ActionSupport{
@DoubleRangeFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
minInclusive = "0.123", maxInclusive = "99.987")
public String getIncome() {
return income;
}
}
EmailValidator注释(验证注释)
如果该字段包含非空字符串,则该验证注释将检查该字段是否为有效的电子邮件地址。
public class Employee extends ActionSupport{
@EmailValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getEmail() {
return email;
}
}
ExpressionValidator注释(验证注释)
此非字段级验证器验证所提供的正则表达式。
@ExpressionValidator(message = "Default message", key = "i18n.key",
shortCircuit = true, expression = "an OGNL expression" )
IntRangeFieldValidator注释(验证注释)
此验证注释检查数字字段是否具有指定范围内的值。如果既不设置min也不设置max,则不会执行任何操作。
public class Employee extends ActionSupport{
@IntRangeFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
min = "0", max = "42")
public String getAge() {
return age;
}
}
RegexFieldValidator注释(验证注释)
此注释使用正则表达式验证字符串字段。
@RegexFieldValidator( key = "regex.field", expression = "yourregexp")
RequiredFieldValidator注释(验证注释)
此验证注释检查字段是否为非空。注释必须在方法级别应用。
public class Employee extends ActionSupport{
@RequiredFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getAge() {
return age;
}
}
RequiredStringValidator注释(验证注释)
此验证注释检查String字段不为空(即非null,长度大于0)。
public class Employee extends ActionSupport{
@RequiredStringValidator(message = "Default message",
key = "i18n.key", shortCircuit = true, trim = true)
public String getName() {
return name;
}
}
StringLengthFieldValidator注释(验证注释)
此验证器检查字符串字段是否具有正确的长度,它假定该字段是一个字符串。如果既没有设置minLength也没有设置maxLength,则不会执行任何操作。
public class Employee extends ActionSupport{
@StringLengthFieldValidator(message = "Default message",
key = "i18n.key", shortCircuit = true,
trim = true, minLength = "5", maxLength = "12")
public String getName() {
return name;
}
}
UrlValidator注释(验证注释)
此验证器检查字段是否是有效的URL。
public class Employee extends ActionSupport{
@UrlValidator(message = "Default message",
key = "i18n.key", shortCircuit = true)
public String getURL() {
return url;
}
}
Validations注释(验证注释)
如果要使用多个相同类型的注释,这些注释必须嵌套在@Validations()注释中。
public class Employee extends ActionSupport{
@Validations(
requiredFields =
{@RequiredFieldValidator(type = ValidatorType.SIMPLE,
fieldName = "customfield",
message = "You must enter a value for field.")},
requiredStrings =
{@RequiredStringValidator(type = ValidatorType.SIMPLE,
fieldName = "stringisrequired",
message = "You must enter a value for string.")}
)
public String getName() {
return name;
}
}
CustomValidator注释(验证注释)
此注释可用于自定义验证器。使用ValidationParameter注释提供其他参数。
@CustomValidator(type ="customValidatorName", fieldName = "myField")
Conversion注释(类型转换注释)
这是类型级别的类型转换的标记注释。转换注释必须在类型级别应用。
@Conversion()
public class ConversionAction implements Action {
}
CreateIfNull注释(类型转换注释)
此注释为类型转换设置CreateIfNull。CreateIfNull注释必须在字段或方法级别应用。
@CreateIfNull( value = true )
private List<User> users;
Element注释(类型转换注释)
此注释设置类型转换的元素。Element注释必须在字段或方法级别应用。
@Element( value = com.acme.User )
private List<User> userList;
Key注释(类型转换注释)
此注释设置类型转换的key。Key注释必须在字段或方法级别应用。
@Key( value = java.lang.Long.class )
private Map<Long, User> userMap;
KeyProperty注释(类型转换注释)
此注释设置类型转换的KeyProperty。KeyProperty注释必须在字段或方法级别应用。
@KeyProperty( value = "userName" )
protected List<User> users = null;
TypeConversion注释(类型转换注释)
此注释用于类和应用程序范围的转换规则。TypeConversion注释可以在属性和方法级别应用。
@TypeConversion(rule = ConversionRule.COLLECTION,
converter = "java.util.String")
public void setUsers( List users ) {
this.users = users;
}