学习Struts2框架笔记-第2天

Struts2中Servlet的API访问

  • 在使用Struts2的框架的过程中,我们发现Struts2和Servlet的API是解耦合的。在实际开发中,经常使用到Servlet的API,比如进行登录,将用户的信息保存到Session中,有的时候需要向页面输出一些内容,用到response对象。这就涉及到Servlet的API的访问。

一、Struts2的Servlet的API的访问(3种方式)

1、完全解耦合的方式:ActionContext对象(基于值栈)

  • 编写JSP(demo1.jsp)
      <h1>Struts2访问Servlet的API</h1>
      <h3>方式一:完全解耦合的方式访问</h3>
      <form action="${ pageContext.request.contextPath}/requestDemo1.action" method="post">
      	姓名:<input type="text" name="name"/><br>
      	密码:<input type="password" name="password"/><br>
      	<input type="submit" value="提交"/>
      </form>
    
  • 编写Action类(RequestDemo1.java)
      package com.heer.struts2.demo1;
      
      import java.util.Arrays;
      import java.util.Map;
      
      import com.opensymphony.xwork2.ActionContext;
      import com.opensymphony.xwork2.ActionSupport;
      
      /**
       * Struts2访问Servlet的API,方式一:完全解耦合的方式,也即根本看不到我们的request对象
       * @author hand
       * 2018年11月27日 下午3:26:19
       */
      public class RequestDemo1 extends ActionSupport {
      
      	@Override
      	public String execute() throws Exception {
      		// 一、接收参数:
      		// 利用Struts2中的对象ActionContext对象
      		ActionContext context = ActionContext.getContext();
      		// 调用ActionContext中的方法
      		// 类似于Map<String,String[]> map = request.getParameter();
      		Map<String, Object> map = context.getParameters();
      		for (String key : map.keySet()) {
      			String[] values = (String[])map.get(key);
      			System.out.println(key+" "+Arrays.toString(values));
      		}
      		// 二、向域对象中存入数据
      		context.put("reqName", "reqValue");// 相当于request.setAttribute();
      		context.getSession().put("sessionName", "sessionValue");// 相当于session.setAttribute();
      		context.getApplication().put("appName", "appValue");// 相当于application.setAttribute();
      		
      		return SUCCESS;
      	}
      }
    
  • 注意:这种方式只能获得代表request、session、application的数据的Map集合,即只能访问域中的数据,不能操作这些对象的本身的方法。

2、使用Servlet的API的原生方式:ServletActionContext对象(习惯使用

  • 编写JSP(demo1.jsp)
      <h3>方式二:使用原生的方式访问</h3>
      <form action="${ pageContext.request.contextPath}/requestDemo2.action" method="post">
      	姓名:<input type="text" name="name"/><br>
      	密码:<input type="password" name="password"/><br>
      	<input type="submit" value="提交"/>
      </form>
    
  • 编写Action类(RequestDemo2.java)
      package com.heer.struts2.demo1;
      
      import java.util.Arrays;
      import java.util.Map;
      
      import javax.servlet.http.HttpServletRequest;
      
      import org.apache.struts2.ServletActionContext;
      
      import com.opensymphony.xwork2.ActionSupport;
      
      /**
       * 访问Servlet的API的方式二:原生的方式
       * @author hand
       * 2018年11月27日 下午4:07:20
       */
      public class RequestDemo2 extends ActionSupport {
      
      	@Override
      	public String execute() throws Exception {
      		// 一、接收数据
      		// 直接获得request对象,通过ServletActionContext
      		HttpServletRequest request = ServletActionContext.getRequest();
      		Map<String, String[]> map = request.getParameterMap();
      		for (String key : map.keySet()) {
      			String[] values = map.get(key);
      			System.out.println(key+" "+Arrays.toString(values));
      		}
      		
      		// 向域对象中保存数据
      		// 向request中保存数据
      		request.setAttribute("reqName", "reqValue");
      		// 向session中保存数据
      		request.getSession().setAttribute("sessionName", "sessionValue");
      		// 向application中保存对象
      		ServletActionContext.getServletContext().setAttribute("appName", "appValue");
      		
      		return SUCCESS;
      	}
      }
    
  • 注意:这种方式可以操作域对象的数据,同时也可以获得对象的方法。

3、接口注入的方式:实现SerbletRequestAware、ServletContextAware、SerbletResponseAware借口(了解)

  • 编写JSP(demo1.jsp)
      <h3>方式三:接口注入的方式访问</h3>
      <form action="${ pageContext.request.contextPath}/requestDemo3.action" method="post">
      	姓名:<input type="text" name="name"/><br>
      	密码:<input type="password" name="password"/><br>
      	<input type="submit" value="提交"/>
      </form>
    
  • 编写Action(RequestDemo3.java)
      package com.heer.struts2.demo1;
      
      import java.util.Arrays;
      import java.util.Map;
      
      import javax.servlet.ServletContext;
      import javax.servlet.http.HttpServletRequest;
      
      import org.apache.struts2.interceptor.ServletRequestAware;
      import org.apache.struts2.util.ServletContextAware;
      
      import com.opensymphony.xwork2.ActionSupport;
      
      /**
       * 访问Servlet的API的方式三:接口注入的方式
       * 实现一个接口,这个接口叫做ServletRequestAware
       * @author hand
       * 2018年11月27日 下午4:26:08
       */
      public class RequestDemo3 extends ActionSupport implements ServletRequestAware,ServletContextAware{
      
      	// 定义一个全局变量,这样setServletRequest方法就会把真实的request对象设置进来
      	private HttpServletRequest request;
      	private ServletContext context;
      
      	@Override
      	public String execute() throws Exception {
      		// 一、接收数据
      		// 直接获得request对象,通过ServletActionContext
      		Map<String, String[]> map = request.getParameterMap();
      		for (String key : map.keySet()) {
      			String[] values = map.get(key);
      			System.out.println(key+" "+Arrays.toString(values));
      		}
      		
      		// 二、向域对象中保存数据
      		// 向request中保存数据
      		request.setAttribute("reqName", "reqValue");
      		// 向session中保存数据
      		request.getSession().setAttribute("sessionName", "sessionValue");
      		// 向application中保存对象,也就是ServletContext,故再实现一个接口
      		context.setAttribute("appName", "appValue");
      		
      		// 此时返回的这个execute()就相当于SUCCESS
      		return super.execute();
      	}
      
      	@Override
      	public void setServletRequest(HttpServletRequest request) {
      		// 这样写需要定义一个全局的变量
      		this.request = request;
      	}
      
      	@Override
      	public void setServletContext(ServletContext context) {
      		this.context = context;
      	}
      }
    
  • 注意:Servlet是单例的,多个程序访问同一个Servlet只会创建一个Servlet的实例。Action是多例的,一次请求,创建一个Action的实例(不会出现线程安全的问题)。

Struts2的结果页面的配置

一、结果页面的配置(2类)

1、全局结果页面

  • 全局结果页面:全局结果页面指的是,在包中配置一次,其他的在这个包中的所有的action只要返回了这个值,都可以跳转到这个页面。多用在返回值相同,跳转同一页面的时候,尤其是返回登录页的时候。
    • 针对这个包下的所有的action的配置都有效。
        <!-- 全局结果页面 -->
        <global-results>
        	<!-- 当全局结果页面进行配置以后,下面的局部就不用再进行配置了,只要返回的结果是success,就会跳转到指定页面 -->
        	<result name="success">/demo1/demo2.jsp</result>
        </global-results>
      

2、局部结果页面

  • 局部结果页面:局部结果页面指的是,只能在当前的action中的配置有效。
    • 针对当前的action有效。
        <?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>
        	<package name="demo1" extends="struts-default" namespace="/">
        		<!-- 全局结果页面 -->
        		<global-results>
        			<!-- 当全局结果页面进行配置以后,下面的局部就不用再进行配置了,只要返回的结果是success,就会跳转到指定页面 -->
        			<result name="success">/demo1/demo2.jsp</result>
        		</global-results>
        		
        		<action name="requestDemo1" class="com.heer.struts2.demo1.RequestDemo1">
        			<!-- 如果局部的和全局的返回值跳转页面不一致,则局部的生效,离action最近的result生效 -->
        			<result name="success">/demo1/demo3.jsp</result>
        		</action>
        		<action name="requestDemo2" class="com.heer.struts2.demo1.RequestDemo2">
        			<!-- <result name="success">/demo1/demo2.jsp</result> -->
        		</action>
        		<action name="requestDemo3" class="com.heer.struts2.demo1.RequestDemo3">
        			<!-- <result name="success">/demo1/demo2.jsp</result> -->
        		</action>
        	</package>
        </struts>
      

二、result标签的配置

1、result标签的配置

  • result标签用于配置页面的跳转。在result标签上有两个属性:
    • name属性:逻辑视图的名称。默认值:success,也就是说,如果返回值是success,可以不写
    • type属性 :页面跳转的类型。(可以在struts-default.xml文件中找到,多种result-types)
      • dispatcher :默认值,请求转发。(Action转发到JSP)
      • redirect :重定向。(Action重定向到JSP)
      • chain :转发。(Action转发到另一个Action)
      • redirectAction :重定向。(Action重定向到另一个Action)
      • stream :Struts2中提供文件下载的功能。

Struts2的数据的封装

  • Struts2框架是一个web层框架,web层框架(框架:软件的办成品,完成一部分的功能)。Struts2提供了数据封装的基本功能。

一、Struts2的数据封装(2大类(属性驱动、模型模型)/3小类)

1、属性驱动:提供属性set方法的方式(不常用)

  • 编写页面(demo1.jsp)
      <h1>Struts2的数据封装</h1>
      <h3>方式一:属性驱动-提供set方法的方式</h3>
      <form action="${ pageContext.request.contextPath }/userAction.action" method="post">
      	用户名:<input type="text" name="username"/>
      	密码:<input type="password" name="password"/>
      	年龄:<input type="text" name="age"/>
      	生日:<input type="text" name="birthday"/>
      	工资:<input type="text" name="salary"/>
      	<input type="submit" name="提交"/>
      </form>
    
  • 编写Action(userAction1.java)
      package com.heer.struts2.demo2;
      
      import java.sql.Date;
      
      import com.heer.struts2.domain.User;
      import com.opensymphony.xwork2.ActionSupport;
      
      /**
       * 数据封装的方式一:提供属性的set方法的方式
       * @author hand
       * 2018年11月27日 下午5:18:23
       */
      public class UserAction1 extends ActionSupport {
      	// 提供了对应的属性
      	private String username;
      	private String password;
      	private Integer age;
      	private Date birthday;
      	private Double salary;
      	
      	// 提供属性对应的set方法
      	public void setUsername(String username) {
      		this.username = username;
      	}
      	public void setPassword(String password) {
      		this.password = password;
      	}
      	public void setAge(Integer age) {
      		this.age = age;
      	}
      	public void setBirthday(Date birthday) {
      		this.birthday = birthday;
      	}
      	public void setSalary(Double salary) {
      		this.salary = salary;
      	}
      
      
      	@Override
      	public String execute() throws Exception {
      		// 接收数据
      		System.out.println(username);
      		System.out.println(password);
      		System.out.println(age);
      		System.out.println(birthday);
      		System.out.println(salary);
      		
      		// 封装数据,需要重新创建对象进行set,所以一般不用,除非当接收数据比较少的情况下才使用
      		User user = new User();
      		user.setUsername(username);
      		user.setPassword(password);
      		user.setAge(age);
      		user.setBirthday(birthday);
      		user.setSalary(salary);
      		
      		return NONE;
      	}
      }
    

2、属性驱动:页面中提供OGNL表达式方式(如果表单是多个对象时,用这个)

  • 编写JSP(demo1.jsp)
      <h3>方式二:属性驱动-在页面中提供OGNL表达式的方式</h3>
      <form action="${ pageContext.request.contextPath }/userAction2.action" method="post">
      	用户名:<input type="text" name="user.username"/>	<br>
      	密码:&nbsp;&nbsp;&nbsp;<input type="password" name="user.password"/><br>
      	年龄:&nbsp;&nbsp;&nbsp;<input type="text" name="user.age"/><br>
      	生日:&nbsp;&nbsp;&nbsp;<input type="text" name="user.birthday"/><br>
      	工资:&nbsp;&nbsp;&nbsp;<input type="text" name="user.salary"/><br>
      	<input type="submit" name="提交"/><br>
      </form>
    
    • 注意:name一定要与类名对应相同,否则是显示不出来的,上面name里面的表达式写法其实是Struts2里面的一个叫做OGNL的表达式。
  • 编写Action类(UserAction2.java)
    • 提供属性的get、set方法

        package com.heer.struts2.demo2;
        			
        import com.heer.struts2.domain.User;
        import com.opensymphony.xwork2.ActionSupport;
        
        /**
         * 数据封装的方式二:属性驱动-在页面中提供表达式的方式
         * @author hand
         * 2018年11月27日 下午5:40:23
         */
        public class UserAction2 extends ActionSupport {
        
        	// 提供一个user对象
        	private User user;
        	
        	// 提供user的set和get方法:一定要提供get方法,不然最后封装完之后只能获取到用户名,其他的都为空。
        	// 因为拦截器完成了数据封装,需要创建User对象。然后通过get方法可以获取同一个对象,将数据封装到同一个对象中。
        	public User getUser() {
        		return user;
        	}
        	public void setUser(User user) {
        		this.user = user;
        	}
        	
        	@Override
        	public String execute() throws Exception {
        		System.out.println(user);
        		
        		return NONE;
        	}
        	
        }
      

3、模型驱动:采用模型驱动方式(最常用

  • 编写JSP(demo1.jsp)
      <h3>方式一:模型驱动-模型驱动的方式</h3>
      <form action="${ pageContext.request.contextPath }/userAction3.action" method="post">
      	用户名:<input type="text" name="username"/>	<br>
      	密码:&nbsp;&nbsp;&nbsp;<input type="password" name="password"/><br>
      	年龄:&nbsp;&nbsp;&nbsp;<input type="text" name="age"/><br>
      	生日:&nbsp;&nbsp;&nbsp;<input type="text" name="birthday"/><br>
      	工资:&nbsp;&nbsp;&nbsp;<input type="text" name="salary"/><br>
      	<input type="submit" name="提交"/><br>
      </form>
    
  • 编写Action类(UserAction3.java),实现一个接口,手动创建对象
      package com.heer.struts2.demo2;
      
      import com.heer.struts2.domain.User;
      import com.opensymphony.xwork2.ActionSupport;
      import com.opensymphony.xwork2.ModelDriven;
      
      /**
       * 数据封装的方式三:模型驱动-模型驱动的方式;
       * 要实现一个模型驱动的接口
       * @author hand
       * 2018年11月27日 下午6:08:50
       */
      public class UserAction3 extends ActionSupport implements ModelDriven<User>{
      
      	// 模型驱动使用的对象:前提必须手动提供对象的实例
      	// 手动实例化User对象
      	private User user = new User();
      	@Override
      	// 模型驱动需要使用的方法
      	public User getModel() {
      		return user;
      	}
      	
      	@Override
      	public String execute() throws Exception {
      		System.out.println(user);
      		return NONE;
      	}	
      }
    
  • 注意:
    • 模型驱动方式是最常用的方式;
    • 缺点:只能同时向一个对象中封装数据。
    • 使用第二种可以向多个对象中同时封装数据:

二、关于INPUT逻辑视图

1、INPUT的逻辑视图的配置

  • Action接口中提供了五个逻辑视图的名称:
    • SUCCESS
    • ERROR
    • LOGIN
    • INPUT :input在某些拦截器中会使用。当输入内容不能转换时就会报input异常,并且是通过日志来进行报错的(要用log4j-1.x的版本或者.xml文件,否则没报错信息),后台没有报错解决办法:在result中添加一个input配置。然后再页面中加上<s:fielderror></s:fielderror>即可展示错误信息。
    • NONE

Struts2的复杂类型的数据封装

  • 在实际开发中,有可能遇到批量向数据库中插入记录,需要在页面中将数据封装到集合中。

一、Struts2的复杂类型的数据封装

1、封装数据到List集合中

  • 编写JSP(demo1.jsp)
      <h1>Struts2的复杂类型的数据封装</h1>
      <h3>封装到List集合中:批量插入商品</h3>
      <form action="${ pageContext.request.contextPath }/productAction1.action" method="post">
      	商品名称:<input type="text" name="products[0].name"/><br>
      	商品价格:<input type="text" name="products[0].price"/><br>
      	商品名称:<input type="text" name="products[1].name"/><br>
      	商品价格:<input type="text" name="products[1].price"/><br>
      	商品名称:<input type="text" name="products[2].name"/><br>
      	商品价格:<input type="text" name="products[2].price"/><br>
      	<input type="submit" value="提交"/><br>
      </form>
    
  • 编写Action
      package com.heer.struts2.demo3;
      
      import java.util.List;
      
      import com.heer.struts2.domain.Product;
      import com.opensymphony.xwork2.ActionSupport;
      
      /**
       * 复杂类型的数据封装:封装到List集合中
       * @author hand
       * 2018年11月27日 下午7:08:43
       */
      public class ProductAction1 extends ActionSupport {
      
      	private List<Product> products;
      	// 提供集合的set方法:
      	public List<Product> getProducts() {
      		return products;
      	}
      
      	public void setProducts(List<Product> products) {
      		this.products = products;
      	}
      	
      	@Override
      	public String execute() throws Exception {
      		for (Product product : products) {
      			System.out.println(product);
      		}
      		return NONE;
      	}
      	
      }
    

2、封装数据到Map集合中

  • 编写JSP(demo1.jsp)
      <h3>封装到Map集合中:批量插入商品</h3>
      <form action="${ pageContext.request.contextPath }/productAction2.action" method="post">
      	<!-- 采用的是map集合的方法,里面的内容自定义,hashMap,输入无序 -->
      	商品名称:<input type="text" name="map['one'].name"/><br>
      	商品价格:<input type="text" name="map['one'].price"/><br>
      	商品名称:<input type="text" name="map['two'].name"/><br>
      	商品价格:<input type="text" name="map['two'].price"/><br>
      	商品名称:<input type="text" name="map['three'].name"/><br>
      	商品价格:<input type="text" name="map['three'].price"/><br>
      	<input type="submit" value="提交"/><br>
      </form>
    
  • 编写Action类(ProductAction2.java)
      package com.heer.struts2.demo3;
      
      import java.util.List;
      import java.util.Map;
      
      import com.heer.struts2.domain.Product;
      import com.opensymphony.xwork2.ActionSupport;
      
      /**
       * 复杂类型的数据封装:封装到Map集合中
       * @author hand
       * 2018年11月27日 下午7:38:43
       */
      public class ProductAction2 extends ActionSupport {
      
      	private Map<String , Product> map;
      	// 提供集合的set方法:
      	public Map<String, Product> getMap() {
      		return map;
      	}
      
      	public void setMap(Map<String, Product> map) {
      		this.map = map;
      	}
      	
      	@Override
      	public String execute() throws Exception {
      		for (String key : map.keySet()) {
      			Product product = map.get(key);
      			System.out.println(key+" "+product);
      		}
      		return NONE;
      	}
      
      }
    

综合练习CRM:保存客户

一、环境搭建

1、修改html改为JSP

二、代码实现

1、保存操作流程

  • 点击左侧的菜单页面页面:
  • 跳转到添加页面(经过Action):
  • 在添加页面中输入指定的信息,点击【保存】
  • 将数据提交到Action–>Service–>DAO
  • 最终回到列表页面

2、第一步:修改菜单页面上链接:

<TBODY>
	<TR>
		<TD class=menuSmall><A class=style2 href="${ pageContext.request.contextPath }/customer_saveUI.action"  target=main>- 新增客户</A></TD>
	</TR>
	<TR> 
		<TD class=menuSmall><A class=style2 href="${ pageContext.request.contextPath }/customer_find.action"
			target=main>- 客户列表</A></TD>
	</TR>
</TBODY>

3、第二步:编写Action中的saveUI的方法

// 跳转保存页面的方法
public String saveUI() {
	return "saveUI";
}

4、第三步:配置页面跳转

<package name="crm" extends="struts-default" namespace="/">
	<action name="customer_*" class="com.heer.web.action.CustomerAction" method="{1}">
		<result name="findSuccess">/jsp/customer/list.jsp</result>
		<result name="saveUI">/jsp/customer/add.jsp</result>
	</action>
</package>

5、第四步:修改添加页面

在这里插入图片描述

6、第五步:完成保存操作

  • 编写Action
      // 跳转保存方法
      	public String save() {
      		// 接收数据
      		// 封装数据
      		// 调用业务层
      		CustomerService customerService = new CustomerServiceImpl();
      		customerService.save(customer);
      		// 页面跳转
      		return "saveSuccess";
      	}
    
  • 编写Service
      @Override
      	// 业务层保存客户的方法
      	public void save(Customer customer) {
      		// 调用Dao
      		CustomerDao customerDao = new CustomerDaoImpl();
      		customerDao.save(customer);
      	}
    
  • 编写DAO
      @Override
      	public void save(Customer customer) {
      		Session session = HibernateUtils.getCurrentSession();
      		Transaction transaction = session.beginTransaction();
      		
      		session.save(customer);
      		
      		transaction.commit();
      	}
    

7、第六步:配置页面的跳转

	<result name="saveSuccess" type="redirectAction">customer_find.action</result>
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值