Struts2(二)

1. 结果视图的配置

1.1 result标签

在sturts.xml文件中,Result的配置非常简单,使用元素来配置Result逻辑视图与物理视图之间的映射,元素可以有name和type属性,但这两种属性都不是必选的。

<action name="demo1" class="com.wgy.web.action.Demo1Action" method="demo1">
    <!-- result标签:
        作用:用于配置结果视图(结果视图可以是一个jsp/html,也可以是一个action)
        属性:
            name:指定逻辑结果视图。作用就是和动作方法的返回值进行比较,当一致时,前往配置的页面或者action。不写的话:默认值是success——>去哪
            type:指定前往结果视图的方式。以何种方式前往。								——>怎么去
                type取值都是来源于struts-default.xml文件中package名称是struts-default包中定义类型
                常用的结果类型:
                dispatcher:请求转发  (默认值)
                redirect:重定向(可以是重定向到另外一个动作或者是重定向到一个jsp)
                redirectAction:重定向到另外一个动作(它由于会自动在后面为我们拼接url后缀,所以只能重定向到动作)
        
                请求转发和重定向的区别:
                请求转发:一次请求	地址栏不变	请求域中数据不丢失	服务器行为	只能是在当前应用中转发
                重定向:  两次请求	地址栏改变	请求域中数据丢失	浏览器行为	可以定向到当前应用的外部
        
                响应浏览器的三种方式:
                    请求转发	重定向	使用流输出(如果只有一种方式,那就是此种方式)
    -->
    <result name="success" type="redirectAction">demo2</result>
    <result name="error" type="dispatcher">/error.jsp</result>
</action>
<action name="demo2">
    <result name="success" type="dispatcher">/success.jsp</result>
    <result name="login">/login.jsp</result>
</action>

1.2 配置全局结果视图

1.2.1 局部结果视图和全局结果视图

配置在action标签内的result,我们成为局部结果视图,它只能由当前action使用。

而在实际开发中,有很多页面,每个action可能都会用到。比如:success.jsp,error.jsp,login.jsp等等。当我们很多action都用到了login.jsp,在每个action标签中都配置一次,显然是不合理的,这个时候我们就用到了全局结果视图。

1.2.2 配置方式

<!-- 定义一个公共包
        全局结果视图和局部结果视图
            定义是放在action标签外面, 在global-results标签内部的结果视图。
            可以在多个action中使用
            优先级:先找局部,再找全局。
-->
<package name="myDefault" extends="struts-default" abstract="true">
    <global-results>
        <result name="login">/login.jsp</result>
    </global-results>
</package>

<package name="p1" extends="myDefault">
    <action name="demo1" class="com.wgy.web.action.Demo1Action" method="demo1">
        <result name="success" type="redirectAction">demo2</result>
    </action>
    
    <action name="demo2">
        <result name="success" type="dispatcher">/success.jsp</result>
        <result name="login">/login.jsp</result>
    </action>
</package>

2. 访问Servlet的API的两种方式

2.1 使用ServletActionContext

/**
 * 访问ServletAPI:
 *  有两种方式:
 *  第一种方式:
 *      使用struts2框架提供的一个工具类,该类中包含了相应的静态方法,可以直接获取
 *      工具类是:ServletActionContext
 *      此种方式是我们实际开发中用的最多的方式
 *
 * 输出结果之后,找出其中一个和其他三个不一样:
 *      org.apache.struts2.dispatcher.StrutsRequestWrapper@1c6e453		它和其他三个不一样,它是struts2提供的
 *      org.apache.catalina.connector.ResponseFacade@b846ae
 *      org.apache.catalina.core.ApplicationContextFacade@287809
 *      org.apache.catalina.session.StandardSessionFacade@e0d480
 *
 * @author wgy
 */
public class Demo1Action extends ActionSupport {
    private HttpServletRequest request;
    private HttpServletResponse response;
    private HttpSession session;
    private ServletContext application;

    /**
     * 动作方法
     *
     * @return
     */
    public String demo1(){
        request = ServletActionContext.getRequest();
        response = ServletActionContext.getResponse();
        application = ServletActionContext.getServletContext();
        session = request.getSession();

        System.out.println(request);
        System.out.println(response);
        System.out.println(application);
        System.out.println(session);
        return SUCCESS;
    }
}

2.2 通过实现接口的方式

image-20200605155121131

/**
 * 访问ServletAPI:
 *  有两种方式:
 *  第二种方式:
 *      通过实现不同的接口,获取不同的对象。
 *      要想使用request,需要实现ServletRequestAware
 *      要想使用response,需要实现ServletResponseAware
 *      要想使用servletContext,需要实现SerlvetContextAware
 *  输出结果之后,找出其中一个和其他三个不一样:
 *      org.apache.struts2.dispatcher.StrutsRequestWrapper@1c6e453		它和其他三个不一样,它是struts2提供的
 *      org.apache.catalina.connector.ResponseFacade@b846ae
 *      org.apache.catalina.core.ApplicationContextFacade@287809
 *      org.apache.catalina.session.StandardSessionFacade@e0d480
 *
 *
 *  如果说是一种方式获取ServletAPI对象:ActionContext中的get(key)
 *  如果说是三种方式获取ServletAPI对象,除了我们讲的两种之外,也可以使用ActionContext获取
 *
 *  通过分析源码,我们得知,ActionContext看上去是一个类似Map的结构。
 *  map的key是String类型,Map的value是Object类型
 *
 * @author wgy
 */
public class Demo2Action extends ActionSupport implements
        ServletRequestAware, ServletResponseAware, ServletContextAware {

    private HttpServletRequest request = null;
    private HttpServletResponse response = null;
    private ServletContext application = null;

    /**
     * 动作方法
     *
     * @return
     */
    public String demo2(){
        System.out.println(request);
        System.out.println(response);
        System.out.println(application);
        return SUCCESS;
    }

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }

    @Override
    public void setServletContext(ServletContext application) {
        this.application = application;
    }
}

3. 请求参数的封装

3.1 请求参数封装概述

封装请求参数就是把我们通过浏览器发送请求时,要转递给服务器的数据封装到指定的对象中。这个对象一般都是实体类。但是有时就是Action中的一个属性。也就是说,我们封装请求参数时,可以有实体类,也可以没有。同时,我们还需要知道,请求参数的封装和请求方式无关。无论get还是post都可以封装。

3.2 属性驱动

3.2.1 没有实体类

此种情况,我们一般也称为动作类和模型在一起,也就是说我们在action中定义一些私有成员,并且提供它们的公有get/set方法。具体代码如下

动作类:

/**
 * 请求参数封装
 * 第一种情况:
 *    属性驱动:没有实体类
 *    表单数据的接收都定义在动作类中,所以称为动作类和模型数据写在一起
 * 要想封装成功,需要按照要求书写:
 *    要求是:表单元素的name属性取值,必须和动作类中成员get/set方法后面的部分保持一致
 *
 * 细节:
 *    1、struts2框架会我们解决post请求的中文乱码问题,但是get请求不解决。
 *    2、struts2框架会自动为我们转换数据类型:
 * 	        基本类型自动转换
 * 	        字符串数组会按照逗号+空格的方式拼接成字符串
 * 	        日期类型会按照本地格式转成日期对象
 * 	            本地格式:yyyy-MM-dd
 *
 * 执行参数封装,是一个名称为params的拦截器实现的。
 * 封装的规则只有一个,它要去指定位置找属性,找到之后调用set方法赋值。
 *
 * @author wgy
 */
public class Demo1Action extends ActionSupport {
    private String username;
    private Integer age;
    private Date birthday;
    private String hobby;

    /**
     * 动作方法
     *
     * @return
     */
    public String demo1(){
        System.out.println(username+"==="+age+"==="+birthday+"==="+hobby);
        return SUCCESS;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

jsp页面:

<%--请求参数封装:第一种情况:属性驱动-没有实体类  --%>
<form action="${pageContext.request.contextPath}/demo1.action" method="post">
    姓名:<input type="text" name="username"/><br/>
    年龄:<input type="text" name="age"/><br/>
    生日:<input type="text" name="birthday"/><br/>
    爱好:<input type="checkbox" name="hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="hobby" value="写代码"/>写代码
    <br/>
    <input type="submit" value="提交"/>
</form>

struts.xml:

<action name="demo1" class="com.wgy.web.action.Demo1Action" method="demo1">
    <result>/success.jsp</result>
</action>

3.2.2 有实体类

此种情况是,我们有独立的实体类,在action中定义的是实体类对象,并且提供get/set方法。代码如下:

动作类:

/**
 * 请求参数封装
 * 第二种情况:
 *    属性驱动:有实体类
 *    表单数据的接收都定义在实体类中,把实体类定义在动作类中。
 * 要想封装成功,需要按照要求书写:
 *   此时需要使用OGNL表达式来指定表单元素的name取值
 *   OGNL表达式全称:Object Graphic Navigation Language
 *                   对象    图	    导航      语言
 *  写法:
 *  	user.username  user.age
 *
 * 执行参数封装,是一个名称为params的拦截器实现的。
 * 封装的规则只有一个,它要去指定位置找属性,找到之后调用set方法赋值。
 *
 * @author wgy
 */
public class Demo2Action extends ActionSupport {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    /**
     * 动作方法
     * @return
     */
    public String demo2(){
        System.out.println(user);
        return SUCCESS;
    }
}

jsp页面:

<%--请求参数封装:第二种情况:属性驱动-有实体类 --%>
<form action="${pageContext.request.contextPath}/demo2.action" method="post">
    姓名:<input type="text" name="user.username"/><br/>
    年龄:<input type="text" name="user.age"/><br/>
    生日:<input type="text" name="user.birthday"/><br/>
    爱好:<input type="checkbox" name="user.hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="user.hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="user.hobby" value="写代码"/>写代码
    <br/>
    <input type="submit" value="提交"/>
</form>

struts.xml:

<action name="demo2" class="com.wgy.web.action.Demo2Action" method="demo2">
    <result>/success.jsp</result>
</action>

3.3 模型驱动

在Struts2中,Action处理请求参数还有另外一种方式,叫做模型驱动(ModelDriven)。通过实现ModelDriven接口来接收请求参数。

动作类:

/**
 * 请求参数封装
 * 第三种情况:		我们在后面用的最多的方式
 *      模型驱动
 * 要想封装成功,需要按照要求书写:
 *  1、动作类必须实现ModelDriven接口
 *  2、动作类中需要定义模型,并且必须实例化出来
 *  3、提供接口抽象方法的实现,返回值必须是模型对象
 *
 * 执行参数封装,是一个名称为params的拦截器实现的。
 * 模型驱动的实现,除了params拦截器之外,还需要一个叫modelDriven的拦截器配合
 * 封装的规则只有一个,它要去指定位置找属性,找到之后调用set方法赋值。
 *
 * @author wgy
 */
public class Demo3Action extends ActionSupport implements ModelDriven<User> {

    private User user = new User();

    @Override
    public User getModel() {
        return user;
    }

    /**
     * 动作方法
     *
     * @return
     */
    public String demo3(){
        System.out.println(user);
        return SUCCESS;
    }
}

jsp页面:

<%--请求参数封装:第三种情况:模型驱动 --%>
<form action="${pageContext.request.contextPath}/demo3.action" method="post">
	姓名:<input type="text" name="username"/><br/>
	年龄:<input type="text" name="age"/><br/>
	生日:<input type="text" name="birthday"/><br/>
	爱好:<input type="checkbox" name="hobby" value="吃饭"/>吃饭
		<input type="checkbox" name="hobby" value="睡觉"/>睡觉
		<input type="checkbox" name="hobby" value="写代码"/>写代码
		<br/>
	<input type="submit" value="提交"/>
</form>

struts.xml:

<action name="demo3" class="com.wgy.web.action.Demo3Action" method="demo3">
    <result>/success.jsp</result>
</action>

3.4 封装集合数据

在实际的开发中,有些时候我们需要批量插入用户或者批量插入其他的对象,在Action中需要接受到这多个Action中封装的对象,然后传递给业务层。那么这个时候就需要将表单的数据封装到集合中。

3.4.1 封装到List

动作类:

/**
 * 请求参数封装
 *  复杂类型的封装:List集合封装
 *  复杂类型的封装都需要基于第二种情况实现
 *
 * @author wgy
 */
public class Demo4Action extends ActionSupport {

    private List<User> users;

    public List<User> getUsers() {
        return users;
    }
    public void setUsers(List<User> users) {
        this.users = users;
    }

    /**
     * 动作方法
     *
     * @return
     */
    public String demo4(){
        System.out.println(users);
        return SUCCESS;
    }
}

jsp页面:

<%--请求参数封装:List集合类型的封装 --%>
<form action="${pageContext.request.contextPath}/demo4.action" method="post">
    姓名:<input type="text" name="users[0].username"/><br/>
    年龄:<input type="text" name="users[0].age"/><br/>
    生日:<input type="text" name="users[0].birthday"/><br/>
    爱好:<input type="checkbox" name="users[0].hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="users[0].hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="users[0].hobby" value="写代码"/>写代码
    <br/>
    姓名:<input type="text" name="users[1].username"/><br/>
    年龄:<input type="text" name="users[1].age"/><br/>
    生日:<input type="text" name="users[1].birthday"/><br/>
    爱好:<input type="checkbox" name="users[1].hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="users[1].hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="users[1].hobby" value="写代码"/>写代码
    <br/>
    <input type="submit" value="提交"/>
</form>

struts.xml:

<action name="demo4" class="com.wgy.web.action.Demo4Action" method="demo4">
    <result>/success.jsp</result>
</action>

3.4.2 封装到Map

动作类:

/**
 * 请求参数封装
 *  复杂类型的封装:Map集合封装
 *  复杂类型的封装都需要基于第二种情况实现
 *
 * @author wgy
 */
public class Demo5Action extends ActionSupport {

    private Map<String, User> users;

    public Map<String, User> getUsers() {
        return users;
    }

    public void setUsers(Map<String, User> users) {
        this.users = users;
    }

    /**
     * 动作方法
     *
     * @return
     */
    public String demo5(){
        System.out.println(users);
        return SUCCESS;
    }
}

jsp页面:

<%--请求参数封装:Map集合类型的封装 --%>
<form action="${pageContext.request.contextPath}/demo5.action" method="post">
    姓名:<input type="text" name="users['key1'].username"/><br/>
    年龄:<input type="text" name="users['key1'].age"/><br/>
    生日:<input type="text" name="users['key1'].birthday"/><br/>
    爱好:<input type="checkbox" name="users['key1'].hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="users['key1'].hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="users['key1'].hobby" value="写代码"/>写代码
    <br/>
    姓名:<input type="text" name="users['abc'].username"/><br/>
    年龄:<input type="text" name="users['abc'].age"/><br/>
    生日:<input type="text" name="users['abc'].birthday"/><br/>
    爱好:<input type="checkbox" name="users['abc'].hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="users['abc'].hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="users['abc'].hobby" value="写代码"/>写代码
    <br/>
    <input type="submit" value="提交"/>
</form>

struts.xml:

<action name="demo5" class="com.wgy.web.action.Demo5Action" method="demo5">
    <result>/success.jsp</result>
</action>

4. 案例:Struts2+Hibernate实现保存删除客户

4.1 Struts2

4.1.1 修改jsp

menu.jsp

<TR>
    <TD class=menuSmall>
        <A class=style2 href="${pageContext.request.contextPath}/customer/addUICustomer.action"  target=main>- 新增客户</A>
    </TD>
</TR>

add.jsp

<FORM id=form1 name=form1 action="${pageContext.request.contextPath }/customer/addCustomer.action" method=post>
    ...
</FORM>

list.jsp

<SCRIPT language=javascript>
	function delOne(custId){
		var sure = window.confirm("确定删除吗?");
		if(sure){
			window.location.href = "${pageContext.request.contextPath}/customer/deleteCustomer?custId="+custId;
		}
	}
</SCRIPT>
<a href="javascript:delOne('${customer.custId}')" >删除</a>

4.1.2 配置xml并编写Action

struts.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <!-- 开启开发者模式 -->
    <constant name="struts.devMode" value="true"></constant>
    <!--  动作配置 -->
    <package name="customer" extends="struts-default" namespace="/customer">
        <!-- 查询所有客户 -->
        <action name="findAllCustomer" class="com.wgy.web.action.CustomerAction" method="findAllCustomer">
            <result name="findAllCustomer">/jsp/customer/list.jsp</result>
        </action>

        <!-- 获取添加客户页面 -->
        <action name="addUICustomer" class="com.wgy.web.action.CustomerAction" method="addUICustomer">
            <result name="addUICustomer">/jsp/customer/add.jsp</result>
        </action>

        <!-- 添加客户 -->
        <action name="addCustomer" class="com.wgy.web.action.CustomerAction" method="addCustomer">
            <!-- <result name="addCustomer" type="redirect">/jsp/success.jsp</result> -->
            <result name="addCustomer" type="redirect">findAllCustomer</result>
        </action>

        <!-- 删除客户 -->
        <action name="deleteCustomer" class="com.wgy.web.action.CustomerAction" method="deleteCustomer">
            <result name="deleteCustomer" type="redirect">findAllCustomer</result>
        </action>
    </package>
</struts>

动作类

/**
 * 客户的动作类
 *
 * @author wgy
 */
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

    private ICustomerService customerService = new CustomerServiceImpl();

    private Customer customer = new Customer();
    @Override
    public Customer getModel() {
        return customer;
    }

    /**
     * 查询所有客户
     * @return
     */
    public String findAllCustomer(){
        //1.调用service查询客户
        List<Customer> customers = customerService.findAllCustomer();
        //2.获取request对象
        HttpServletRequest request = ServletActionContext.getRequest();
        //3.把查询的结果存入请求域中
        request.setAttribute("customers", customers);
        //4.返回
        return "findAllCustomer";
    }

    /**
     * 获取添加客户页面
     * @return
     */
    public String addUICustomer(){
        return "addUICustomer";
    }

    /**
     * 添加客户
     * @return
     */
    public String addCustomer(){
        customerService.saveCustomer(customer);
        return "addCustomer";
    }

    /**
     * 删除客户
     * @return
     */
    public String deleteCustomer(){
        customerService.deleteCustomer(customer);
        return "deleteCustomer";
    }
}

4.2 Hibernate

4.2.1 编写业务层接口及实现类

/**
 * 客户的业务层接口
 *
 * @author wgy
 */
public interface ICustomerService {

    /**
     * 查询所有客户
     *
     * @return
     */
    List<Customer> findAllCustomer();

    /**
     * 添加客户
     *
     * @param customer
     */
    void saveCustomer(Customer customer);

    /**
     * 删除客户
     * @param customer
     */
    void deleteCustomer(Customer customer);
}
/**
 * 客户的业务层实现类
 * 事务控制在业务层的
 *
 * @author wgy
 */
public class CustomerServiceImpl implements ICustomerService {

    private ICustomerDao customerDao = new CustomerDaoImpl();

    @Override
    public List<Customer> findAllCustomer() {
        Session s = null;
        Transaction tx = null;
        try{
            //1.获取Session
            s = HibernateUtil.getCurrentSession();
            //2.开启事务
            tx = s.beginTransaction();
            //3.执行操作
            List<Customer> customers = customerDao.findAllCustomer();
            //4.提交事务
            tx.commit();
            //5.返回结果
            return customers;
        }catch(Exception e){
            //回滚事务
            tx.rollback();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveCustomer(Customer customer) {
        Session s = null;
        Transaction tx = null;
        try{
            //1.获取Session
            s = HibernateUtil.getCurrentSession();
            //2.开启事务
            tx = s.beginTransaction();
            //3.执行操作
            customerDao.saveCustomer(customer);
            //4.提交事务
            tx.commit();
        }catch(Exception e){
            //回滚事务
            tx.rollback();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteCustomer(Customer customer) {
        Session s = null;
        Transaction tx = null;
        try{
            //1.获取Session
            s = HibernateUtil.getCurrentSession();
            //2.开启事务
            tx = s.beginTransaction();
            //3.执行操作
            customerDao.deleteCustomer(customer);
            //4.提交事务
            tx.commit();
        }catch(Exception e){
            //回滚事务
            tx.rollback();
            throw new RuntimeException(e);
        }
    }
}

4.2.2 编写持久层接口及实现类

/**
 * 客户的持久层接口
 *
 * @author wgy
 */
public interface ICustomerDao {

    /**
     * 查询所有客户
     *
     * @return
     */
    List<Customer> findAllCustomer();

    /**
     * 添加客户
     * @param customer
     */
    void saveCustomer(Customer customer);

    /**
     * 删除客户
     * @param customer
     */
    void deleteCustomer(Customer customer);

    /**
     * 根据id查询客户
     * @param custID
     * @return
     */
    Customer findCustomerById(Long custID);
}
/**
 * 客户的持久层实现类
 *
 * @author wgy
 */
public class CustomerDaoImpl implements ICustomerDao {

    @Override
    public List<Customer> findAllCustomer() {
        return HibernateUtil.getCurrentSession().createQuery("from Customer").list();
    }

    @Override
    public void saveCustomer(Customer customer) {
        HibernateUtil.getCurrentSession().save(customer);
    }

    @Override
    public void deleteCustomer(Customer customer) {
        HibernateUtil.getCurrentSession().delete(findCustomerById(customer.getCustId()));
    }

    @Override
    public Customer findCustomerById(Long custID) {
        return HibernateUtil.getCurrentSession().get(Customer.class,custID);
    }
}

5. 请求参数封装失败后处理办法

5.1 配置input结果视图

视图路径应该是从哪来回哪去

<action name="demo3" class="com.wgy.web.action.Demo3Action" method="demo3">
    <result>/success.jsp</result>
    <result name="input">/user.jsp</result>
</action>

5.2 提示错误信息

引入struts2标签库

<%@ taglib uri="/struts-tags" prefix="s" %>
<%--请求参数封装:类型转换失败的处理方式 --%>
<form action="${pageContext.request.contextPath}/demo3.action" method="post">
    姓名:<input type="text" name="username"/><s:fielderror fieldName="username"/><br/>
    年龄:<input type="text" name="age"/><s:fielderror fieldName="age"/><br/>
    生日:<input type="text" name="birthday"/><s:fielderror fieldName="birthday"/><br/>
    爱好:<input type="checkbox" name="hobby" value="吃饭"/>吃饭
    <input type="checkbox" name="hobby" value="睡觉"/>睡觉
    <input type="checkbox" name="hobby" value="写代码"/>写代码
    <s:fielderror fieldName="hobby"/><br/>
    <input type="submit" value="提交"/>
</form>

5.3 把提交的数据回显回来

html标签和struts2标签都可以实现

<s:form action="demo3">
	<s:textfield name="username" label="姓名"/>
	<s:textfield name="age" label="年龄"/>
	<s:textfield name="birthday" label="生日"/>
	<s:submit value="提交"/>
</s:form>

5.4 关于中文提示的问题

I18N : 国际化 Internationalization

同实体类创建.properties文件

invalid.fieldvalue.birthday=请输入正确的日期格式。正确的格式是:yyyy-MM-dd
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值