Android+SSH综合项目实践

第29讲 Android+SSH综合项目实践

一、需求分析,设计数据库

本例采用mysql数据库,数据库名为News,采用MySql Manager建立表达字段和约束。

 

首先修改系统上mysql的编码为utf8

 

建立数据库的时候采用utf8

 

 

 

建立表的时候用utf8

 

设置外键约束

数据库中字段的详细

二、搭建ssh框架环境

2.1 struts框架的搭建

(1)在Myeclipse中新建一个Web工程,使用JavaEE 5.0,添加struts框架进去

复制struts所需要的jar包进入工程(参考示例工程)

(2)在web.xml中加入启动struts的过滤器

       <filter>

              <filter-name>struts2</filter-name>

       <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

       </filter>

       <filter-mapping>

              <filter-name>struts2</filter-name>

              <url-pattern>/*</url-pattern>

       </filter-mapping>

 

(3)创建struts.xml配置文件(参考blank示例工程中复制过来)

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="" namespace="/" extends="struts-default">

        <action name=" " class=" ">

        </action>   

    </package>

</struts>

 

(4)创建整个工程的包目录

dao:持久层

service:业务层代码,将来可以作为切面,实现业务拦截,代码增强

action:控制层代码

orm:数据模型,实体类,以及映射文件

interceptor:Struts的拦截器

util:其他的工具类

 

2.2为工程添加spring框架

(注意:不要把所有的spring的包都复制进去,因此,在添加框架的时候,不要选择复制jar文件)

(1)选中工程,右键——add Spring …..

 

(2)选择创建一个新的applicationContext.xml配置文件:

 

(3)复制Spring的基本包进入工程:

spring-framework-2.5.5-with-dependencies\spring-framework-2.5.5\dist\ spring.jar

spring-framework-2.5.5-with-dependencies\spring-framework-2.5.5\lib\ jakarta-commons\commons-logging.jar

 

复制AspectJ和Annotation所需要用到的包:

spring-framework-2.5.5\lib\aspectj\ aspectjrt.jar

spring-framework-2.5.5\lib\aspectj\ aspectjweaver.jar

 

(4)复制Spring的struts插件包进去:(在struts2和spring结合的时候,必须使用这个包,后面有讲到,在后面添加也可以)

struts-2.3.1.2\lib\struts2-spring-plugin-2.3.1.2.jar

 

2.3 配置struts和spring的结合

(1)先配置好Struts2,然后将Spring2.5配置进来。(先确保Struts2配置正常,这个前面已经完成,三个部分:添加Struts相关包、添加struts.xml文件、在web.xml中添加struts的配置)

(2)将struts2-spring-plugin-2.3.1.2.jar复制到工程中,注意这个是在struts的包下(前面2.4节已经复制进去了)

 

在我们集成struts2+spring+hibernate,也就是所谓的S2SH,不可避免的要引入struts2-spring- plugin.jar插件。当引入这个插件后,原先所struts创建的action类,交给了spring创建。在struts2-spring- plugin.jar中有一个struts-plugin.xml,里面声明了action类由spring工厂创建。在struts2插件文档里,这样写着“The Spring Plugin works by overriding the Struts ObjectFactory to enhance the creation of core framework objects这个插件重写了struts的对象工厂,当创建一个action类时,它会根据struts的配置文件的class属性的值与 spring配置文件中的id属性的值相匹配。如果没有与之相匹配,将会像没有使用这个插件前一样创建,然后由spring自动装配。

 

在web.xml中编写自动启动Spring框架的监听器,并且制定spring配置文件applicationContext.xml的位置,指定给参数contextConfigLocation。(见下面代码方框中的内容)

 

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5"

    xmlns="http://java.sun.com/xml/ns/javaee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><!--

   

<!-- 指定Spring的配置文件位置 -->

<context-param>

        <param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/classes/applicationContext.xml</param-value>

</context-param>

   

<!-- 指定以Listener方式启动Spring容器 -->

    <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

<!-- 指定以Listener方式启动Log4j -->

    <listener>

    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>

    </listener>

<!-- 定义Struts2的核心控制器,前面已经配置好了-->  

    <filter>

        <filter-name>struts2</filter-name>

<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>struts2</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

</web-app>

 

(3)在struts.xml中添加一个常量struts.objcetFactory,表示action对象都由spring框架来创建,如下红色部分代码:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <constant name="struts.objcetFactory" value="spring"></constant>

    <package name="" namespace="/" extends="struts-default">

        <action name=" " class=" ">

        </action>

    </package>

</struts>

 

(4)加入sping框架后,编写一个Action的配置方法,就不再是只限于在struts.xml中配置了。

 

需要分为两步:首先在Spring配置文件applicationContext.xml中装配Struts的Action实例,即将Action配置为一个bean,交由Spring来统一管理。然后将这个bean的id,作为action的class属性,配置到struts.xml中去。

注意:一旦配置了spring框架,struts.xml中的actionclass属性,就不再是Action的类全名,而是Spring中定义的beanid名。

 

2.4 为工程添加Hibernate框架

(1)在此之前,需要在MyEclipse中添加一个数据库的驱动

 

(2)工程上点击右键,将Hibernate框架添加进去

选择将jar包复制到工程中来

 

 

选择不创建SessionFactory,因为我们在Spring中来创建

 

点击finish,出现自动生成的applicationContext.xml配置文件,里面会找不到BasicDataSource

    <bean id="dataSource"

       class="org.apache.commons.dbcp.BasicDataSource">

需要将…\spring-framework-2.5.5-with-dependencies\spring-framework-2.5.5\lib\jakarta-commons\common-dbcp.jar,common-pool.jar添加进去

 

DBCP(DataBase connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。参考书上使用的是c3p0,也是连接池组件。

c3p0与dbcp区别

  dbcp没有自动的去回收空闲连接的功能

  c3p0有自动回收空闲连接功能

 

 

(2)使用逆向工程将数据库生成相应的pojo和orm映射文件

 

先添加数据驱动,切换到Database视图,将数据库加到MyEclipse中来。

 

Update hibernate configuration with mapping 这项打勾是自动更新applicationContext.xml中的映射配置文件列表,下一步,选择主键生成器为native——完成。

逆向工程完成后,可以查看到,在orm包中有自动生成的实体类和hibernate映射配置文件。

 

还可以查看到,applicationContext.xml中有自动生成的相关代码

 

(3)在applicationContext.xml中添加如下三句代码

<prop key = "hibernate.show_sql">true</prop>

<prop key="hibernate.format_sql">true</prop>

<!-- 设置Hibernate是否在控制台输出SQL语句,开发调试阶段通常设为true -->

<!-- 设置Hibernate一个提交批次中的最大SQL语句数 -->

<prop key="hibernate.jdbc.batch_size">50</prop>

 

 

添加后,在执行hibernate的数据库操作时,会在控制台打印出sql语句:

 

三、代码编写部分

3.1 实现步骤概述

(1)编写数据库访问层dao、业务层service

编写好 XxxDao. javaXxxDaoImpl. java以及XxxService. javaXxxServiceImpl. java。设置daoservice层次的依赖注入关系,在applicationContext.xml中进行配置,并测试daoservice的各个方法的可用性,再进行下一步操作。

(2)编写控制层代码action

编写XxxAction.java,设置actionservice的依赖关系,分别在applicationContext.xmlstruts.xml中配置相关的Action,在浏览器上测试action的有效性,再用Android客户端来访问。

http://localhost:8080/Demo1/RegisterAction?username=xiaoming&password=456&realname=xiaoming

(3)编写Android端程序,设置Android的HttpClient访问的url为上述的Action的地址。

 

 

3.2 user表的操作为例,演示整个ssh框架的编写过程。

1、编写UserDao和UserDaoImpl

package com.demo.dao;

import com.demo.orm.User;

public interface UserDao {

    public void saveUser(User u);

}

 

public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

    public void saveUser(User u) {

       this.getHibernateTemplate().save(u);

    }

}

 

在applicationContext.xml中配置UserDaoImpl

<bean id="UserDaoImpl" class="com.demo.dao.impl.UserDaoImpl">

           <property name="sessionFactory" ref="sessionFactory"></property>

</bean>

 

用main函数测试

    public static void main(String [] args){

       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

       UserDaoImpl userDaoImpl =(UserDaoImpl) context.getBean("UserDaoImpl");

       User u = new User();

       u.setRealname("汤姆");

       u.setUsername("tom");

       u.setPassword("123");

       userDaoImpl.saveUser(u);

    }

 

2、编写业务层UserService、UserServiceImpl,注意和UserDao的依赖注入关系。

public interface UserService {

    public void register(User u);

}

public class UserServiceImpl implements UserService{

    UserDao dao;

    public UserDao getDao() {

       return dao;

    }

    public void setDao(UserDao dao) {

       this.dao = dao;

    }

    public void register(User u) {

       dao.saveUser(u);

    }

}

 

<bean id="UserServiceImpl" class="com.demo.service.impl.UserServiceImpl">

           <property name="dao" ref="UserDaoImpl"></property>

</bean>

 

在main中测试UserService

    public static void main(String [] args){

       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

       UserServiceImpl us =(UserServiceImpl) context.getBean("UserServiceImpl");

       User u = new User();

       u.setRealname("李磊");

       u.setUsername("lilei");

       u.setPassword("123");

       us.register(u);

    }

 

3、编写控制层代码RegisterAction

public class RegisterAction extends ActionSupport implements ServletRequestAware,ServletResponseAware{

    //获取到request response对象

    HttpServletRequest request;

    HttpServletResponse response;

    public void setServletRequest(HttpServletRequest request) {

       this.request=request;

    }

    public void setServletResponse(HttpServletResponse response) {

       this.response=response;

      

    }

    UserService userService;

    public void setUserService(UserService userService) {

       this.userService = userService;

    }

    public String execute() throws Exception {

       String username = request.getParameter("username");

       String password = request.getParameter("password");

       String realname = request.getParameter("realname");

       User u = new User();

       u.setPassword(password);

       u.setRealname(realname);

       u.setUsername(username);

      

       userService.register(u);

       response.getWriter().write("success");

       return null;

    }

}

在applicationContext.xml中对RegisterAction进行配置,注意依赖UserService

    <bean id="RegisterAction" class="com.demo.action.RegisterAction">

       <property name="userService" ref="UserServiceImpl"></property>

    </bean>

struts.xml中对RegisterAction进行配置

<struts>

    <constant name="struts.objcetFactory" value="spring"></constant>

    <package name="default" namespace="/" extends="struts-default">

        <action name="RegisterAction" class="RegisterAction">

        </action>

    </package>

</struts>

 

 

4、在浏览器中测试LoginAction

http://localhost:8080/Demo1/RegisterAction?username=xiaoming&password=456&realname=xiaoming

 

5、编写Android客户端的用户注册界面,用户注册的业务类、用户注册的Activity。

(1)编写注册的业务类,将数据发送到服务器,得到返回的结果,是注册成功、失败、还是连接网络失败。

(2)编写Android的注册界面及Activity

注意:向服务器提交数据的中文编码问题(见22讲)

 

 

 

 

3.3 用户登录部分

1、服务器端:持久层UserDao、UserDaoImpl添加一个业务方法

 

    public User findUserByNameAndPw(String username, String pw) {

       List<User> list = (List<User>)this.getHibernateTemplate().find(

              "from User as u where u.username=? and u.password = ?",

              new Object[] { username, pw });

       if(list.size()>0){

           return list.get(0);

       }

       return null;

    }

2、业务层、控制层依次调用

 

3、页面上测试登录的url

 

4、在Android端编写登录的相关代码。

 

3.4 对已经注册的用户进行管理(服务器端完成)

 

3.5 对新闻的管理(服务器端完成)

 

3.6 客户端显示新闻列表(使用JSON封装客户端和服务器端交换的数据)

3.6.1 服务器端部分

1、编写NewsDaoImpl NewsServiceImpl

 

 2、NewsAction,将List封装的新闻列表以json格式发送到客户端

需要用到JSONArray工具类,需要将其jar包导入到工程中

 

public class NewsAction  extends ActionSupport implements ServletRequestAware,ServletResponseAware{

    NewsService service;

    public NewsService getService() {

       return service;

    }

    public void setService(NewsService service) {

       this.service = service;

    }

    HttpServletRequest request;

    HttpServletResponse response;

    public void setServletRequest(HttpServletRequest request) {

       this.request = request;

    }

 

    public void setServletResponse(HttpServletResponse response) {

       this.response=response;

    }

    @Override

    public String execute() throws Exception {

       List<News> list = service.listAllNews();

       //将所有的List中的信息以json的形式写入到客户端

       JSONArray a = new JSONArray(list);

       System.out.println(a.toString());

       response.setContentType("text/html;charset=utf-8");

       response.getWriter().print(a.toString());

       return null;

    }

}

 

在浏览器中测试Action:

http://192.168.101.62:8080/Demo1/NewsAction

 

单条JSON数据格式如下:

"id":1,

"newsTilte":"我院举办2013年\u201c廉洁·诚信\u201d校园辩论赛",

"newsContent":"本次辩论赛是学院根据《省委教育工委 省教育厅关于举办全省高校首届大学生\u201c廉洁·诚信\u201d主题辩论赛的通知》文件精神,结合我院思政课教学实践活动开展的,旨在深入学习贯彻党的十八大精神,扎实推进廉洁文化进校园活动,引导大学生增强理性思辨能力、诚实守法意识和廉洁自律意识,提高思想道德水平,培养合格的社会主义建设者和接班人。学院非常重视本次比赛,专门成立了辩论赛领导小组,由思政部、党办、学工处、纪委监查审计室和各系联合承办,演讲与口才协会协办。",

"stauts":1,

"publishDate":"2013-06-26 00:00:00.0"

 

},

"picture":{"id":1,"hibernateLazyInitializer":{"unwrap":false,"persistentClass":"class com.demo.orm.Picture","identifier":1,"uninitialized":true,"entityName":"com.demo.orm.Picture"}},

"newstype":{"id":1,"hibernateLazyInitializer":{"unwrap":false,"persistentClass":"class com.demo.orm.Newstype","identifier":1,"uninitialized":true,"entityName":"com.demo.orm.Newstype"}},

 

 

3.6.2 客户端部分

1、编写客户端访问新闻列表数据的业务类NewsService

将收到得客户端的json格式的新闻数据,通过工具类JSONArray,再次重组成List<News>对象。

 

 

public class NewsService {

    public List<News> getAllNewsList(){

       String basePath = "http://192.168.101.62:8080/Demo1/NewsAction";

       try {

           URL url = new URL(basePath);

           HttpURLConnection conn = (HttpURLConnection) url.openConnection();

           conn.setConnectTimeout(5000);

           conn.setRequestMethod("GET");

           if(conn.getResponseCode()==200){

              Log.i("test""网络连接成功,采用Get方法提交数据");

              InputStream is = conn.getInputStream();

              BufferedReader br = new BufferedReader(new InputStreamReader(is));

              String result ="";

              String line="";

              while((line=br.readLine())!=null){

                  result+=line;

              }

              Log.i("test", result);

              List <News> list = new ArrayList<News>();

              JSONArray jSONArray = new JSONArray(result);

              for(int i = 0;i<jSONArray.length();i++){

                  JSONObject object = jSONArray.optJSONObject(i);

                  String newsTilte = (String) object.get("newsTilte");

                  String newsContent = (String) object.get("newsContent");

                  String publishDate = (String) object.get("publishDate");

                 

                  JSONObject newspic = object.getJSONObject("picture");

                  int newspicId = (Integer) newspic.get("id");

 

                  JSONObject newstype = object.getJSONObject("newstype");

                  int newstypeId = (Integer) newstype.get("id");

                 

                  News news = new News(newstypeId, newspicId, newsTilte,

                         newsContent, publishDate);

                  list.add(news);

              }

              return list;

           }

       } catch (Exception e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

       return null;

    }

 

}

 

2、编写新闻标题列表的Activity及界面

界面略

 

public class ListNewsActivity extends Activity {

    ListView lv;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_list_news);

       lv = (ListView) this.findViewById(R.id.lv_news);    

       NewsService service = new NewsService(); 

       List<News> newslist = service.getAllNewsList(); 

       List<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();

       for(News news:newslist){

           HashMap<String, Object> map= new HashMap<String, Object>();

           map.put("newstilet", news.getNewsTilte());

           map.put("newscontent", news.getNewsContent());

           map.put("publishdate", news.getPublishDate());

           map.put("newstpye_id", news.getNewstypeId());

           map.put("newspic_id", news.getPictureId());

           data.add(map);

       }     

       SimpleAdapter adapter = new SimpleAdapter(this,data,

                R.layout.item,new String[]{"newstilet","publishdate"}, new int[]{R.id.tv_newstitle,R.id.tv_newstime});

      

       lv.setAdapter(adapter);

    }

}

 

3.7 单个新闻显示页面

1、编写单个新闻显示的Activity,编写单个新闻显示的界面(线性布局)

2、在新闻列表Activity中编写单个列表项的选项点击事件:

lv.setOnItemClickListener(new OnItemClickListener(){

           @Override

           public void onItemClick(AdapterView<?> parent, View view,

                  int position, long id) {

              String news_title= newslist.get(position).getNewsTilte();

              String news_content = newslist.get(position).getNewsContent();

              String news_time = newslist.get(position).getPublishDate();

              int newspic_id = newslist.get(position).getPictureId();

             

              //跳转到单个新闻显示页面,用Intent将数据传输过去(代码略)

             

           }});

 

3.8 图片的显示

在客户端只能得到新闻的图片id,希望通过图片id能显示到该张图片

1、在服务器端编写一个程序,得到客户端提交的图片id,查询到图片的具体地址,编写一个专用于显示图片的Action

public class ImageAction extends ActionSupport implements ServletRequestAware,ServletResponseAware{

    HttpServletRequest request;

    HttpServletResponse response;

    public void setServletRequest(HttpServletRequest request) {

       this.request = request;

    }

 

    public void setServletResponse(HttpServletResponse response) {

       this.response=response;

    }

    //客户端就通过:http://localhost:8080/Demo1/ImageAction?pic_id=3 来访问图片

    public String execute() throws Exception {

       int pic_id = Integer.parseInt(request.getParameter("pic_id"));

       //做一个查询,通过pic_id得到图片的具体的地址(代码略)

       //假设这个地址已经获得,是

        String pic_add="aa.jpg";

        //http://localhost:8080/Demo1/pic/aa.jpg

        response.setContentType("image/jpeg");

        OutputStream out = response.getOutputStream();

        FileInputStream in = new FileInputStream(request.getRealPath("pic")+"/"+pic_add);  //得到图片的服务器的文件的输入流

       //将图片的输入流,写入客户端的输出流

        if(in!=null){

        byte [] b= new byte[1024];

        int len=0;

        while((len=in.read(b))!=-1){

            out.write(b, 0, len);

        }

        }

        out.flush();

       return null;

    }

}

 

2、在浏览器中测试,看是否能

通过:http://localhost:8080/Demo1/ImageAction?pic_id=3 来访问图片

 

3、编写客户端访问图片的程序,将图片显示到客户端的ImageView上,详细代码见第22讲网络图片的查看

 


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值