从MVC和三层架构说到ssh整合开发-下

最后更新于:2022-04-01 14:17:38

> 这章主要讲整合开发,直接从实战讲起,对与ssh的单方面了解,请继续等待我的后续文章。 ### 讲解不到位的地方欢迎大家指正:联系方式rlovep.com ### 详细请看源代码注释: 全部代码下载(csdn):[链接](http://download.csdn.net/detail/peace1213/9412233) Github链接:[链接](https://github.com/wpeace1212/javaBlog/tree/master/sshDemo)[https://github.com/wpeace1212/javaBlog/tree/master/sshDemo](https://github.com/wpeace1212/javaBlog/tree/master/sshDemo) 写文章不易,欢迎大家采我的文章,以及给出有用的评论,当然大家也可以关注一下我的github;多谢; ## 1.整合流程 针对一个简单项目,让大家对三层机构和MVC有一个简单的认识,以及怎样整合ssh框架; **1.整合的项目介绍:** 1. 企业人事管理系统!要求对员工信息进行维护。 1. 后台系统先登陆,才能操作员工: 添加/修改/删除 1. 没有登陆,只能查看列表,不能操作! **2.功能分类:** 1. 管理员模块:对应AdminAction中实现 登陆/注册 2. 员工模块:对应EmployeeAction中实现 添加一个员工, 指定添加的部门 对指定的员工信息修改 删除选择员工 列表展示 **3.需要的技术:** 1. Struts2:对是否登陆的拦截,对各个功能请求的分别处理,模型驱动。 2. Hibernate4:建立多对一关系的数据库,以及实现增删改查 表t_admin:存放管理员信息 表t_dept:存放部门信息,要用到one-to-many关联员工表 表t_employee:存放员工信息,要用到many-to-one关联部门表 3. Spring:实现bean对象的创建管理,整合,事务管理 4.大体按照下面的流程进行介绍:设计数据库直接在实体存中实现 1. Jar包引入 1. entity层映射 1. Spring配置 1. hibernate配置 1. Dao层 1. Service层 1. web.xml配置 1. struts.xml配置 1. Action层 1. jsp层 **三层架构:其中2,4,5步是数据访问层,3,6步是业务逻辑层,7,9,10步表现层** **MVC:其中2,3,4,5,6步是模型层,7,9,步是控制层,10步是视图层** 5.工程简图: ![00](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0015b7a91.png "") ### 2.Jar包下载     第一步当然是建立web项目、引入jar文件、准备环境了,建立就不介绍了,只介绍最小包的引入: 我的最小包下载地址(ssh最小包):[http://download.csdn.net/detail/peace1213/9412092](http://download.csdn.net/detail/peace1213/9412092) - **1.Struts 2.3.16.1** 下载地址:[http://struts.apache.org/download](http://struts.apache.org/download) Struts中需要引入的包:struts-2.3.16.1/apps/struts2-blank/WEB-INF/lib:该lib下面的包都可以引入; ![01](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0015d1472.png "") - **2.spring-framework-4.2.3.RELEASE-dist.zip** 下载地址:[http://repo.springsource.org/libs-release-local/org/springframework/spring/](http://repo.springsource.org/libs-release-local/org/springframework/spring/) 需要引入的包: ![03](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0015ea22a.png "") - **3.Hibernate 4.1.6** 下载地址:[http://sourceforge.net/projects/hibernate/files/hibernate4](http://sourceforge.net/projects/hibernate/files/hibernate4) 需要引入的包: ![02](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001614ce0.png "") - **4.Aopalliance 1.0** 该包在struts的lib中有 下载地址:[http://sourceforge.net/projects/aopalliance](http://sourceforge.net/projects/aopalliance) ~~~ aopalliance.jar ~~~ - **5.Aspectj 1.7.0** 下载地址:[http://www.eclipse.org/aspectj/downloads.php](http://www.eclipse.org/aspectj/downloads.php) ~~~ aspectjrt.jar aspectjweaver.jar ~~~ - **6.Cglib 2.2.3** 下载地址:[http://sourceforge.net/projects/cglib/files](http://sourceforge.net/projects/cglib/files) ~~~ cglib-2.2.3.jar ~~~ - **7.Asm 3.3** 该包在struts的lib中有 下载地址:[http://forge.ow2.org/projects/asm](http://forge.ow2.org/projects/asm) ~~~ asm-3.3.jar ~~~ - **8.Log4j 1.2.17** 该包在struts的lib中有 下载地址:[http://logging.apache.org/log4j/1.2/download.html](http://logging.apache.org/log4j/1.2/download.html) ~~~ log4j-1.2.17.jar ~~~ - **9.mysql-connector-java-5.1.37-bin.jar** 下载地址:[http://dev.mysql.com/downloads/connector/j](http://dev.mysql.com/downloads/connector/j) ~~~ mysql-connector-java-5.1.37-bin.jar ~~~ - **10.Commons Logging 1.1.1** 该包在struts的lib中有 下载地址:[http://commons.apache.org/logging](http://commons.apache.org/logging) ~~~ commons-logging-1.1.1.jar ~~~ 其他需要引入的jar: ![04](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0016339f5.png "") ### 3.entity层映射 1.需要建立三个实体类:Admin.java,Dept.java,Employee.java,如下: ~~~ 此处都省略get和set方法: public class Admin { private int id; private String adminName; private String pwd; ...... public class Dept { private int id; private String name; private Set<Employee> emps=new LinkedHashSet<>(); ...... public class Employee { private int id; private String empName; private double salary; private Dept dept; ...... ~~~ 2.建立对应的映射文件:×.hbm.xml ~~~ 1.Admin.hbm.xml: <class name="Admin" table="t_admin"> <id name="id"> <generator class="native"></generator> </id> <property name="adminName" length="20"></property> <property name="pwd" length="20"></property> </class> 2.Dept.hbm.xml: <class name="Dept" table="t_dept"> <id name="id" > <generator class="native"></generator> </id> <property name="name" column="Dname"></property> <set name="emps" cascade="save-update,delete" table="t_employee" > <key column="dept_id"></key> <one-to-many class="Employee"></one-to-many> </set> 3.Employee.hbm.xml: <class name="Employee" table="t_employee"> <id name="id"> <generator class="native"></generator> </id> <property name="empName" length="20"></property> <property name="salary" type="double"></property> <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> </class> ~~~ ## 4.Spring配置 : Spring分为:bean-base.xml,bean-dao.xml,bean-service.xml,bean-action.xml,以及整合成一个的bean.xml 辞去暂时介绍bean-base.xml基础功能文件和bean.xml,其他文件到相应的介绍地方再进行介绍; 1.bean-base.xml:主要配置Hibernate的工厂sessionFactory和事务,连接池 ~~~ <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 1. 数据源对象: C3P0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day01?useUnicode=true&amp;characterEncoding=UTF8"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> <property name="initialPoolSize" value="3"></property> <property name="maxPoolSize" value="10"></property> <property name="maxStatements" value="100"></property> <property name="acquireIncrement" value="2"></property> </bean> <!-- ###########Spring与Hibernate整合 start########### --> <!-- 【推荐】方式所有的配置全部都在Spring配置文件中完成 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <!-- 注入连接池对象 --> <property name="dataSource" ref="dataSource"></property> <!-- Hibernate常用配置 --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> <!-- hibernate映射配置--> <property name="mappingLocations"> <list> <value>classpath:com/rlovep/entity/*.hbm.xml</value> </list> </property> </bean> <!-- ###########Spring与Hibernate整合 end########### --> <!-- 事务配置 --> <!-- a. 配置事务管理器类 --> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- b. 配置事务增强(拦截到方法后如果管理事务?) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" read-only="false"/> </tx:attributes> </tx:advice> <!-- c. Aop配置 --> <aop:config> <aop:pointcut expression="execution(* com.rlovep.service.impl.*.*(..))" id="pt"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config> <!-- 用于建表 --> <bean id="appDao" class="com.rlovep.entity.AppDao"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> </beans> ~~~ 2.bean.xml: ~~~ ....省略..... <!-- 引入其他配置文件 --> <import resource="config/bean-base.xml"/> <import resource="config/bean-dao.xml"/> <import resource="config/bean-service.xml"/> <import resource="config/bean-action.xml"/> </beans> ~~~ ## 5.Hibernate配置: Spring中已经配置好了Hibernate,此处主要讲解建立数据库中的三个表; 1. 建立AppDao类文件:bean已经在bean.hbm.xml中配置了 ~~~ /* * 用来创建数据库中的表 */ public class AppDao { //工厂通过spring注入 private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } //@Test public void test(){ //sessionFactory=(SessionFactory)ac.getBean("sessionFactory"); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); //保存管理员,并创建表 Admin admin=new Admin(); admin.setAdminName("admin"); admin.setPwd("123456"); session.save(admin); //保存部门和雇员,并创建表 Dept dept1=new Dept(); Dept dept2=new Dept(); ....省略..... //持久化 session.save(dept1); ....省略..... session.save(employee4); tx.commit(); session.close(); } ~~~ 2.建立类App类创建数据库和存数据: ~~~ public class App { private ApplicationContext ac=new ClassPathXmlApplicationContext("config/bean-base.xml"); @Test public void test(){ //ac.getBean("deptDao"); AppDao appDao = (AppDao)ac.getBean("appDao"); appDao.test(); } } ~~~ 3.点击运行App的test方法就可以完成数据库的创建; ## 6.Dao层:实现数据增删改查; 1.先建立接口: IAdminDao,IDepDao,IEmployee,IBaseDao(所有Dao的通用操作接口定义) 此处只贴出IBaseDao接口的定义: ~~~ /* * * 所有dao的通用操作接口定义 */ public interface IBaseDao<T> { /** * 保存 * @param obj */ void save(T obj); ....省略..... } ~~~ 2.接口的实现:AdminDao,DepDao,Employee,BaseDao(所有Dao的通用操作,希望所有的dao都继承此类) BaseDao实现: ~~~ /* * 所有dao的通用操作,希望所有的dao都继承此类 */ public class BaseDao<T> implements IBaseDao<T>{ //当前操作实际的bean类型 private Class<T>clazz; //获取类名称 private String className; // IOC容器(依赖)注入SessionFactory对象 private SessionFactory sessionFactory; public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public BaseDao() { Type type=this.getClass().getGenericSuperclass(); //转换为参数化类型 ParameterizedType pt=(ParameterizedType)type;// BaseDao<Employee> //得到实际类型 Type types[]=pt.getActualTypeArguments(); //获取实际类型 clazz=(Class<T>)types[0]; className = clazz.getSimpleName();//例如:Employee } ....省略..... @Override public List<T> getAll() { Query query = sessionFactory.getCurrentSession().createQuery("from "+className); List<T> list = query.list(); return list; } } ~~~ 其他接口实现: ~~~ //只需要继承通用操作,和特点接口就行:这里接口中没有方法,可以加方法 public class DeptDao extends BaseDao<Dept> implements IDepDao{ } ~~~ ## 7.Service层: 同样先建立接口再建立类,此处不贴出代码,介绍bean-dao.xml,bean-service.xml的建立,以及对刚刚建立的Dao和service进行测试 1.bean-dao.xml ~~~ <!-- dao实例 --> <bean id="adminDao" class="com.rlovep.dao.impl.AdminDao"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="deptDao" class="com.rlovep.dao.impl.DeptDao"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="employeeDao" class="com.rlovep.dao.impl.EmployeeDao"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> ~~~ 2.bean-service.xml ~~~ <!-- service 实例 --> <bean id="adminService" class="com.rlovep.service.impl.AdminService"> <property name="adminDao" ref="adminDao"></property> </bean> <bean id="deptService" class="com.rlovep.service.impl.DeptService"> <property name="deptDao" ref="deptDao"></property> </bean> <bean id="employeeService" class="com.rlovep.service.impl.EmployeeService"> <property name="employeeDao" ref="employeeDao"></property> </bean> ~~~ 3.测试刚刚建立的dao和service: 在包service中建立App测试类: ~~~ public class App { //加载spring的配置文件 private ApplicationContext ac=new ClassPathXmlApplicationContext("bean.xml"); //测试Admin的操作 @Test public void testAdmin(){ //获得bean IAdminService adminService=(IAdminService)ac.getBean("adminService"); Admin admin=new Admin(); admin.setAdminName("admin"); admin.setPwd("123456"); System.out.println( adminService.login(admin)); } //测试Dept的操作 @Test public void testDept(){ IDeptService service=( IDeptService)ac.getBean("deptService"); System.out.println( service.findById(1)); } //测试Employee的操作 @Test public void testEmployee(){ IEmployeeService service=( IEmployeeService)ac.getBean("employeeService"); List<Employee> list = service.getAll(); System.out.println( service.findById(9)); } } ~~~ ## 8.web.xml配置: 1. 需要配置Spring 1. 需要配置Struts2 1. 配置文件如下: ~~~ <?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>sshDemo</display-name> <!-- 配置spring的OpenSessionInView模式 【目的:JSp页面访问懒加载数据】 --> <!-- 注意:访问struts时候需要带上*.action后缀 --> <filter> <filter-name>OpenSessionInView</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>OpenSessionInView</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <!-- Struts2的配置 --> <filter> <!-- 配置过滤器的名字 --> <filter-name>struts2</filter-name> <!-- 配置核心过滤器类 --> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <!--配置要拦截的URL,辞去配置全部拦截 --> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--在web.xml中加入如下代码令服务器自动加载Spring --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:bean.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 首页配置 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> ~~~ ## 9.struts.xml配置 : 1.由于spring的整合,在 struts.xml配置文件中的class属性直接使用:spring的配置文件bean-action.xml中定义的bean 2.struts.xml文件: ~~~ <package name="struts2" extends="struts-default"> <!-- 配置action,class属性使用Spring中定义的bean-> <action name="admin_*" class="adminAction" method="{1}"> <!-- 登陆失败 --> <result name="loginFaild">/login.jsp</result> <!-- 登陆成功 --> <result name="index" type="redirectAction">emp_list</result> </action> <action name="emp_*" class="employeeAction" method="{1}"> <!-- 列表展示 --> <result name="list">/WEB-INF/list.jsp</result> <!-- 进入添加页面视图 --> <result name="add">/WEB-INF/add.jsp</result> <!-- 添加成功,进入列表 (防止刷新就多一条记录问题,所以用重定向) --> <result name="listAction" type="redirectAction">emp_list</result> <!-- 进入修改页面 --> <result name="edit">/WEB-INF/edit.jsp</result> </action> ~~~ 3.bean-action.xml文件: ~~~ <!-- 指定action多例 --> <bean id="adminAction" class="com.rlovep.action.AdminAction" scope="prototype"> <property name="adminService" ref="adminService"></property> </bean> <bean id="employeeAction" class="com.rlovep.action.EmployeeAction" scope="prototype"> <property name="deptService" ref="deptService"></property> <property name="employeeService" ref="employeeService"></property> </bean> ~~~ ## 10.Action层 : 1. 建立AdminAction文件:继承ActionSupport类,和实现ModelDriver接口 1. 建立EmployeeAction文件:继承ActionSupport类,和实现ModelDriver接口 1. 建立拦截器类:AdminInterceptor类用于判断是否登陆;继承AbstractInterceptor ~~~ @Override public String intercept(ActionInvocation invocation) throws Exception { //得到当前执行的方法 String method = invocation.getProxy().getMethod(); //判断:当不为登陆方法和list方法时 if(!"login".equals(method)&&!"list".equals(method)){ Object obj= ActionContext.getContext().getSession().get("adminInfo"); if(obj==null){ //没有登陆 return "login"; }else{ //放行 return invocation.invoke(); } } //放行 return invocation.invoke(); } ~~~ ### 11.建立相应的jsp文件: 主要有:index,login,edit,add,list等jsp文件;详情见工程源代码; ## 11.测试图:部署动态工程 1. 测试登陆 ![4](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00164a594.gif "") 1. 测试添加 ![5](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00166ab8c.gif "") 1. 测试删除 ![6](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001692ef0.gif "") 1. 测试修改 ![7](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0016b3e73.gif "") 好的本章介绍到这里 来自伊豚wpeace(rlovep.com)
';

从MVC和三层架构说到ssh整合开发-上

最后更新于:2022-04-01 14:17:34

> 相信很多人都认同JavaWeb开发是遵从MVC开发模式的,遵从三层架构进行开发的,是的,大家都这么认同。但是相信大家都会有过这样一个疑问,if(MVC三层模式==三层架构思想)out.println(“请继续观看……”) ## 1.MVC(Model-View-Controller)设计模式: 首先让我们了解下MVC(Model-View-Controller)的概念:      MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。 1. Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,主要提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。主要使用的技术:数据模型:实体类(JavaBean),数据访问:JDBC,Hibernate等, 1. View(视图):负责进行模型的展示,一般就是我们见到的用户界面,比如JSP,Html等 1. Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。主要使用的技术:servlet,Struts中的Action类等。      MVC是一个框架模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。最典型的MVC就是JSP + servlet + javabean的模式。 ![01](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001561d25.png "") ## 2.层架构(UI-BLL-DAL)思想介绍:      三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:表现层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。区分层次的目的即为了“高内聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层。 1. 表现层(UI):通俗讲就是展现给用户的界面,用于显示数据和接收用户输入的数据,为用户提供一种交互式操作的界面。 1. 业务逻辑层(BLL):针对具体问题的操作,也可以说是对数据层的操作,对数据业务逻辑处理。对于数据访问层而言,它是调用者;对于表示层而言,它却是被调用者。也将业务逻辑层称为领域层。 1. 数据访问层(DAL):该层所做事务直接操作数据库,针对数据的增、删、改、查。如果要加入ORM的元素,那么就会包括对象和数据表之间的mapping,以及对象实体的持久化。也称为是持久层。数据访问层中包含实体层(Model 实体层) JavaWeb中典型的三层架构是:Jsp+Struts/Spring+Hibernate的开发模式 ## 3.MVC和三层架构的区别与转化: 1. MVC与三层架构的概念区别: MVC是一种设计模式,我们可以用它来创建在域对象和UI表示层对象之间的区分。它是根据项目的具体需求来决定是否适用于该项目。 三层架构是一个分层式的软件体系架构设计,它可适用于任何一个项目。      三层架构和MVC设计模式侧重点不一样,三层是一种笼统的架构思想,没有限制具体的设计;而MVC就比较具体的说明它的设计方法。我们从接手一个项目开始,首先,我们需要进行架构设计,一般我们采用的就是分层式的架构设计,即我们的三层架构。然后,在确定了架构以后,我们再根据项目的具体需求去考虑是否需要应用一些设计模式,比如是否应用我们的MVC模式,抽象工厂模式等等。      三层侧重的是整体的一个解耦,而MVC侧重的是web系统的解耦,即侧重jsp和Servlet的一个解耦。 1. MVC与三层架构的划分层次区别: 三层架构将整个项目划分为:表现层(UI)、业务逻辑层(BLL)、数据访问层(DAL)。 MVC :即Model(模型),View(视图),Controller(控制)。 下图可以说明他们的区别与联系:通过图中可以看到不是一一对应的关系:V是UI,C是BLL,M是DAL的观点是错误的。 ![02](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001585530.png "") 1. 两者间的转化:      在我们项目中选择了三层架构的基础上在根据具体需求决定是否需要使用MVC,于是我们常说的MVC中总是伴随着三层架构,也就造成了两者的容易混淆。其实,通过上图我们可以看到MVC将三成架构中的UI分成了控制层和试图层。将三层架构中的数据访问层和业务逻辑层整合成了模型层。 ## 4. 针对三层架构的MVC模式开发讲解SSH框架: ### 4.1 ssh介绍: SSH多个框架(struts2+spring+hibernate)的集成,是目前较流行的一种企业及Web应用程序开源集成框架。 1. Struts2:      Struts2是流行和成熟的基于MVC设计模式的Web应用程序框架。 Struts2不只是Struts1下一个版本,它是一个完全重写的Struts架构。Struts对Model,View和Controller都提供了对应的组件。但是在ssh开发过程中主要用Struts作为三层架构中的表现层,也就是MVC中的View和Control层。 Struts2提供了表单提交参数封装成POJO类,提交参数的类型转换,输入校验,文件的上传下载,程序的国际化,Struts2标签,以及对AJAX的支持。 1. Hibernate:      Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,说的简单点:就是功能更加强大的JDBC。      Hibernate实现了对象到数据库端的封装。就是常说的ORM(Object Relation Mapping),它的出现使得编程更加的面向对象,在传统的编程上,我们要将对象存储到关系数据库中,需要写很多代码来实现,而且需要考虑跨数据库的平台的问题。有了Hibernate可以方便的实现从对象转换到关系数据库。这就是对象持久化。 1. Spring:      主要包含两个重要功能:IOC和AOP,也就是常说的依赖注入和面向切面编程。当然还有Spring的事务功能,不过这一功能是在结合前面两者的功能实现的。      IOC:依赖注入(控制反转),是一种设计模式。一层含义是控制权的转移:由传统的在程序中控制依赖转移到由容器来控制;第二层是依赖注入:将相互依赖的对象分离,在spring配置文件中描述他们的依赖关系。他们的依赖关系只在使用的时候才建立。简单来说就是不需要NEW一个对象了。      AOP这是一种面向切面的编程思想,这种思想使得编程思想上得到了历史性的进步。它将程序的执行过程切割成不同的面,在面之间可以插入我们想执行的逻辑。 ### 4.2 ssh的层次划分: 一进行javaWeb开发很多时候我们按照这样的层次进行划分: 1、在表示层中,首先通过JSP页面实现交互界面,负责传送请求(Request)和接收响应(Response),然后Struts根据配置文件(struts-config.xml)将ActionServlet接收到的Request委派给相应的Action处理,然后action进行对请求处理并转发给JSP页面。 2、在业务逻辑层中,管理服务组件的Spring IoC容器负责向Struts2提供具体的Action对象,提供业务模型(Model)组件和该组件的协作对象数据处理(DAO)组件完成业务逻辑,并提供事务处理、缓冲池等容器组件以提升系统性能和保证数据的完整性。 3、在数据访问层中,则依赖于Hibernate的对象化映射和数据库交互,处理DAO组件请求的数据,并返回处理结果,给业务逻辑层。 按照MVC模式时:Jsp对应着表现层,struts2对应控制层,Spring和Hibernate对应模型层。 分层不是绝对的,每个人的见解是不一样的,仅供参考; ![03](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00159a422.png "") 从MVC说道ssh整合开发上就介绍到这里,下部分主要是对ssh框架的整合,会介绍怎么使用ssh取开发一个简单的web应用。 来自一条小鲨鱼wpeace(rlovep.com)
';

Mysql入门实战中

最后更新于:2022-04-01 14:17:32

> 前面一章主要讲解了mysql的入门学习,包括数据库,表的管理,以及对数据的增删改,本章主要介绍mysql最重要的语句select的用法,将select的大部分用法进行分别讲解。 全部代码下载(csdn):[链接](http://download.csdn.net/detail/peace1213/9398233) Github链接:[链接](https://github.com/wpeace1212/Mysql) ### 1.select语句简单介绍: select语句从语义上就可以知道主要是用来进行查询的 1. 数据表都已经创建起来了,我们已经插入了许多的数据,我们可以用自己喜欢的方式对数据表里面的信息进行检索和显示了。比如说显示我们建立的表student所有的数据: `select * from student;` 显示如下: ![01](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00148308a.png "") 1. select语法格式: ~~~ 1. 简单语法: select [字段] from 表名 where 条件判断 2. 复杂的语法: SELECT select_list --描述结果集的列 INTO new_table_name --指定使用结果集来创建新表 FROM table_list --包含从中检索到结果集数据的表的列表[返回结果集的对象]。 [ WHERE search_conditions ] --WHERE 子句是一个筛选,它定义了源表中的行要满足 SELECT 语句的要求所必须达到的条件 [ GROUP BY group_by_list ] --根据 group_by_list 列中的值将结果集分成组 [ HAVING search_conditions ] --结果集的附加筛选 [ ORDER BY order_list [ ASC | DESC ] ] --结果集的附加筛选 ~~~ ### 2.简单查询: ### 2.1查询指定字段 第一部分介绍的 select * from student;中的*号是通配符,意思查询的全部列,平时我们经常要查询的可能只是名字或者分数,这是就可以指定字段进行查找 1. 语法格式: `SELECT 字段名 FROM 表名;` 1. 演示如下:选择指定字段为sname,mark的两列 ~~~ select sname,mark from student; ~~~ 1. 可以使用as关键字为字段定义别名: 如: ~~~ -- 查询指定的列 并指定别名as-- select sname,sid as id from student; ~~~ 显示如下: ![02](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0014926f8.png "") 1. 查询时可以添加常量列,比如某个学生都属于2014级自动化班: ~~~ -- 增加一个班级列,内容为:自动化班 字段名称为2014级 -- select sid,sname,'自动化班' as '2014级' from student; ~~~ ### 2.2限制查询行数:也叫分页查询; 当我们数据库很大时为了显示或处理方便可以使用分页查询: - **1.语法格式**: ~~~ select * from student limit [index],[count];行数不足,返回行数为实际值 或者: select * from student limit [count] OFFSET [index]; ~~~ index数为开始位置的前一行,count数为要检索的行数; - **2. 演示如下**:选出student的从第二行开始的3行 ~~~ -- 限制查询行数 -- select sid,sname from student limit 1,3; ~~~ - **3**. 还可以选择倒叙或者升序:desc降序,asc升序 ~~~ -- 查询排序 Desc降序排序 -- select * from student order by sid Desc limit 1,3; ~~~ - **4. 注意**: 在给出order by子句时,应该保证他位于 from子句之后。如果使用limit,他必须位于order by子句之后,使用子句的次序不对将产生错误消息 ### 3.复杂查询: ### 3.1查询之过滤: 数据库表一般包含大量的数据,很少需要检索表中所有行。通常会根据特定操作或报告的需要提取表数据的子集。 - **1.语法格式**: `select * from student where 条件;` 如:查询sid=2的学生: ~~~ -- 检查单个值-- select * from student where sid=002; select * from student where sid<>002; ~~~ - **2.支持的子句操作符**: ![03](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0014a478b.png "") - **3.范围过滤**: 为了检查某个范围的值,可使用between操作符: `语法:select from***where***between***and***` 如:sid在002到004之间 `演示:select * from student where sid between 002 and 004;` - **4.空值检查**: 在创建表时,表设计人员可以指定其中的列是否可以不包含值。在一个列不包含值时,被称作包含空值null: `语法: select ***from***where***is***null` 如: `演示:select * from student where sgender is null;` - **5.条件逻辑过滤**: 为了进行更强的过滤控制,MySQL允许给出多个where子句。这些子句可以两种方式使用:以and子句的方式或or子句的方式使用: `语法:select * from student where 条件1 and(or) 条件2;` 如:选择sid==001和002并且mark大于1 `演示:select * from student where (sid=001 or sid=002) and mark>1;` 注意:and和or的组合带来了一个问题——计算次序:and操作符的优先级高于or.所以上面演示的时候将or语句用括号包围了 - **6.In操作符**: in操作符用来指定范围,范围中的每个条件都可以进行匹配。in取合法值的由逗号分隔的清单,全部括在圆括号中 `语法:select ***from***where in (清单)` 如:选择出sid在(001,002,003)中 `演示:select * from student where sid in (001,002,003);` 为什么要使用IN操作符?其优点如下 在使用长的合法选项清单时,In操作符的语法更加清楚而且更直观  在使用IN时计算的次序更容易管理 ,IN操作符一般比OR操作符清单执行更快 IN的最大优点是可以包含其他select语句,似的能够更动态的建立where子句 - **7.not操作符**: WHERE子句中的NOT操作符有且只有一个功能,那就是否定它之后的任何条件。 如否定刚刚的in条件: `select * from student where sid not in (001,002,003);` - **8.使用通配符**: 用来匹配值的一部分的特殊字符, 为在搜索句子中使用通配符,必须使用like操作符。like指示mysQL后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。 在搜索串中,%表示任何字符出现任意次数 下划线的用途与%一样,但下划线只匹配单个字符而不是多个字符 演示如下: ~~~ -- 用通配符进行过滤 like % _-- -- 选出名字中含有eac的词-- select * from student where sname like '%eac%'; -- 选出第一个字符任意,后面字符为eace的词-- select * from student where sname like '_eace'; ~~~ - **9.用正则表达式**: 正则表达式的作用是匹配文本,将一个模式(正则表达式)与一个文本串进行比较。关键字为regexp;正则表达式搜索与like比较相似;此去只做简单演示; ~~~ -- 正则表达式,不同于like,使用的操作符是regexp,匹配的也是含有-- -- 基本字符匹配-- select sname from student where sname regexp 'ong';-- 此去如果用like不会返回结果,因为不加通配符时,like时完全匹配; -- 正则书写部分基本与其他正则语言一致-- select sname from student where sname regexp '[peac,ron]'; select * from student where sid regexp '[[:digit:]]'; ~~~ ### 3.2查询之计算字段: 查询可以对一些字段进行算术运算,包括加减乘除; 1. concat()函数来拼接两个列。 ~~~ -- 拼接-- select concat(sname,'(',sid,')') as sname from student; ~~~ 1. +,-,×,/用来计算字段: ~~~ -- 执行算法计算-- select sid,sname,sid*mark as imark from student; ~~~ ### 3.3使用函数: 对获得的数据进行处理比如对获得的字符串处理,对日期处理,对数值处理; - **1.支持的函数**: ![04](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0014c03a8.png "") ![05](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0014dbe8f.png "") ![06](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00150706f.png "") - **2.简单演示**: ~~~ -- 文本处理函数-- select sname,upper(sname) from student; -- 日期和时间处理函数-- student -- select c_id,order_num from orders where date(order_date)='2015-11-4'; -- 数值处理函数-- select sid,sname from student where mod(sid,2)=0; ~~~ ### 3.4汇总数据(合计函数): - **1.avg max, min, sum合计函数** Sum函数返回满足where条件的行的和 AVG函数返回满足where条件的一列的平均值 Max/min函数返回满足where条件的一列的最大/最小值 演示: ~~~ select avg(sid) as avg, min(sid) as min, max(sid) as max, sum(sid) as sum from student; -- 聚集不同的值 --distinct不相等的值 select avg(distinct mark) from student; ~~~ - **2.count函数**: Count(列名)返回某一列,行的总数 演示: ~~~ select count(*) from student; select count(sage) from student; ~~~ ### 3.5数据分组: 在SQL的语法里,GROUP BY和HAVING子句用来对数据进行汇总。GROUP BY子句指明了按照哪几个字段来分组,而将记录分组后,用HAVING子句过滤这些记录。 - **1.语法**: ~~~ #以column1 为一组计算 column2 的平均值 SELECT column1, column2. column3.. FROM table group by column1 使用having 子句过滤: SELECT column1, column2. column3..FROM table group by column1 having ... ~~~ **注意**:Having和where均可实现过滤,但在having可以使用合计函数,having通常跟在group by后,它作用于组。 - **2. 简单演示**: ~~~ -- 数据分组 group by-- select mark,count(*) as num from student group by mark; -- 过滤分组having num>2-- select mark,count(*)as num from student where sid>1 group by mark having num>2; -- 注意having有where的功能,但where不可以替代having,where用于过滤结果,having用于过滤分组结果-- ~~~ ### 3.6子句顺序: – select子句顺序– – select–from–where–group by–having–order by–limit– ### 4.多表查询: 多表查询规则:1)确定查询哪些表 2)确定哪些哪些字段 3)表与表之间连接条件 (规律:连接条件数量是表数量-1) ### 4.1子查询: 子查询可以理解为 套查询.子查询是一个Select语句. - **1.分为三种方式**: 1. 表达式的值与子查询返回的单一值做比较 表达式 comparision [ANY|ALL|SOME](#) 1. 检查表达式的值是否匹配子查询返回的一组值的某个值 [NOT]IN(子查询) 1. 做为计算字段使用子查询 - **2.演示如下**: ~~~ ##使用子查询 ###1. 使用表达式的值与子查询返回的单一值做比较 --主查询返回单价比任何一个折扣大于等于25%的产品的单价要高的所有产品 Select * FROM Products Where UnitPrice 〉ANY (Select UnitPrice FROM[Order Details] Where Discount〉0.25) ###2. 检查表达式的值是否匹配子查询返回的一组值的某个值 -- 1检查detil的所有goods编号 -- 2检查具有前一步骤列出的编号的所有goods商品 select * from goods where goods_id in (select goods from detil); ###3.做为计算字段使用子查询 -- 1从goods检索商品列表 -- 2对于检索的每个商品id,统计其出现在detil的次数: select *,(select count(*) from detil where detil.goods=goods_id) as id_count from goods; #必须写全表名,防止混淆 ~~~ ### 4.2内连接查询: 通过连接运算符可以实现多个表查询。连接是关系数据库模型的主要特点,连接操作给用户带来很大的灵活性,他们可以在任何时候增加新的数据类型。为不同实体创建新的表,尔后通过连接进行查询。 - **1.定义**: 内连接(inner join或者join,也可以使用逗号)只返回两个表中连接字段相等的行; ~~~ ##内连接连接二表的例子: select * from 表1 inner join 表2 on 表1.字段号=表2.字段号 或:select * from 表1 ,表2 where 表1.字段号=表2.字段号 ##内连接连接三表的例子: select * from (表1 inner join 表2 on 表1.字段号=表2.字段号) inner join 表3 on 表1.字段号=表3.字段号 ##内连接四表的例子: select * from ((表1 inner join 表2 on 表1.字段号=表2.字段号)inner join 表3 on表1.字段号=表3.字段号)inner join 表4 on 表1.字段号=表4.字段号 ~~~ - **2.演示如下**: ~~~ -- 使用内连接 -- 1 列出goods_name,goods_price客户够买的数量 ,使用逗号写 select detil.customer_id as id,goods.goods_name as g_name,goods.gooods_price as price,detil.count as count,(goods.gooods_price * detil.count) as expensive from goods,detil where goods_id=detil.goods order by id;#这种通过测量相等的为内部联接; -- 2.使用内部方式写 select detil.customer_id as id,goods.goods_name as g_name,goods.gooods_price as price,detil.count as count,(goods.gooods_price * detil.count) as expensive from goods inner join detil on goods_id=detil.goods order by id; ---- 自联接,与多表内连接一样 -- 1.先找出有问题的饼干4对应的商品id -- 2.通过商品id找到对应id生产的所有商品; select p1.goods_name,p1.goods_maker from goods as p1,goods as p2 where p1.goods_id=p2.goods_id and p2.goods_name='饼干4'; ~~~ ### 4.3外接查询: MySQL中的外连接,分为左外连接和右连接,即除了返回符合连接条件的结果之外,还要返回左表(左连接)或者右表(右连接)中不符合连接条件的结果,相对应的使用NULL对应。 - **1.左右连接**: 左连接(left join)返回左表中所有记录和右表中连接字段相等的记录 右连接(right join)返回右表中所有记录和左表中连接字段相等的记录 如果两个表中字段并不完全一一对应,想要那些没有对应的字段也显示出来就可以使用左连接和右连接查询,一个是包括左边所有,一个是包括右边; ~~~ ##左连接两表的例子: select * from 表1 left join 表2 on 表.字段号=表2.字段号; ##左连接三表查询的例子: select * from (表1 left join 表2 on 表1.字段号=表2.字段号) left join 表3 on 表2.字段号=表3.字段号 ##右连接两表的例子: select * from 表1 right join 表2 on 表.字段号=表2.字段号; ##右连接三表查询的例子: select * from (表1 right join 表2 on 表1.字段号=表2.字段号)right join 表3 on 表2.字段号=表3.字段号 ~~~ - **2.演示如下**: ~~~ -- 外部连接: 将没有关联的数据页查询出来;left查询出左边表(goods)所有的,right将右边表的所有查询; select detil.customer_id as id,goods.goods_name as g_name,goods.gooods_price as price,detil.count as count,(goods.gooods_price * detil.count) as expensive from goods left outer join detil on goods_id=detil.goods order by id; ~~~ ### 4.4组合(联合)查询: - **1.定义**: 把两次或多次的查询结果合并起来,要求查询的列数一致,推荐查询的对应的列类型一致,可以查询多张表,多次查询语句时如果列名不一样,则取第一次的列名!如果不同的语句中取出的行的每个列的值都一样,那么结果将自动会去重复,如果不想去重复则要加all来声明,即union all。 简单理解:union 跟where的多个or条件一样; 语法: ~~~ ##同一张表: select 字段1,字段2 from table1 where 条件 union select 字段1,字段2 from table1 where 条件 ##不同的表:要求字段1,2和字段3,4类型一致 select 字段1,字段2 from table1 where 条件 union select 字段3,字段4 from table2 where 条件 ~~~ - **2.演示如下**: ~~~ ##组合查询 select goods_id,goods_name from goods where goods_id>2 union select goods_id,goods_name from goods where goods_name in ('饼干1','饼干3') order by goods_id; ~~~ ### 4.5 笛卡尔积(交叉连接)查询: - **1.定义**: 笛卡尔积返回的结果为被连接的两个数据表的乘积: 假设现在有两张表A和B:如下 A表: ![07](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001525086.jpg "") B表: ![08](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00153757f.jpg "") 则查询的笛卡尔积如下:select * from A,B; ![09](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001548d95.jpg "") - **2.语法**: ~~~ ##在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用',' 如: SELECT * FROM table1 CROSS JOIN table2 SELECT * FROM table1 JOIN table2 SELECT * FROM table1,table2 ~~~ - **3.演示如上**: 好的本章介绍到这里 来自一条小鲨鱼wpeace(rlovep.com)
';

Mysql入门实战上

最后更新于:2022-04-01 14:17:30

> 前面讲解了Mysql的安装以及连接工具。本文是Mysql入门实战的上,主要讲解mysql服务的启动与停止,数据库管理,表管理以及数据的增删改; ### [源码下载地址](https://github.com/wpeace1212/Mysql/blob/master/hello.sql) ### 1.Mysql服务的启动,停止 一般只要你安装好了,每次启动电脑时mysql服务都是自动启动的。当然mysql也有他自己的启动停止等命令; ### 1.1windows下Mysql的启动与停止: 在 Windows 命令提示符下运行: 启动: net start MySQL 停止: net stop MySQL 重启: net restart MySQL ### 1.2Linux下Mysql的启动与停止: 1. 启动: 使用 service 启动:service mysql start 使用 mysqld 脚本启动:/etc/inint.d/mysql start 使用 safe_mysqld 启动:safe_mysql& 1. 停止: 使用 service 启动:service mysql stop 使用 mysqld 脚本启动:/etc/inint.d/mysql stop mysqladmin shutdown 1. 重启: 使用 service 启动:service mysql restart 使用 mysqld 脚本启动:/etc/inint.d/mysql restart ### 2.数据库管理: ### 2.1登陆到mysql: 当 MySQL 服务已经运行时, 我们可以通过MySQL客户端工具登录到MySQL数据库中: 命令如下: ~~~ mysql -h 主机名 -u 用户名 -p -h : 该命令用于指定客户端所要登录的MySQL主机名, 登录当前机器该参数可以省略; -u : 所要登录的用户名; -p : 告诉服务器将会使用一个密码来登录, 如果所要登录的用户名密码为空, 可以忽略此选项。 如登陆本地的: peace@peace-rong:~$ mysql -u root -p Enter password: #键入你安装时用的密码 Welcome to the MySQL monitor. Commands end with ; or \g. ~~~ 登陆后就可以使用mysql的sql命令了 ~~~ SQL语句的分类: DDL: 数据定义语言: create / drop / alter DML:数据操作语句: insert / delete /update / truncate DQL: 数据查询语言:select / show ~~~ **注意**:MySQL语句以分号(;)作为语句的结束, 若在语句结尾不添加分号时, 命令提示符会以 -> 提示你继续输入(有个别特例, 但加分号是一定不会错的); ### 2.2查询所有数据库: 命令:show databases;注意分号结尾 ~~~ mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema |-- mysql元数据,基础数据 | day01 |--这是我自己建立的数据库 | mysql |--mysql配置数据库,其中包含用户信息。(用户名和密码,权限管理) | performance_schema |--mysql数据库软件的运行数据,日志信息,性能数据 | test | --测试数据库。空的 +--------------------+ 5 rows in set (0.00 sec) mysql> ~~~ ### 2.3创建数据库: 要使用数据库你得先创建自己的数据库: 1. 语法格式: ~~~ create database 数据库名 [其他选项]; ~~~ 其中其他选项可选; 1. 实践: 创建一个数据库day01并且指定默认字符级为utf-8;注意在sql中需要写成utf8 ~~~ create database day01 default character set utf8; ##创建成功返回结果如下: Query OK, 1 row affected (0.00 sec) ~~~ 你可以查看刚刚创建的数据库的默认字符集: ~~~ show create database day01; ##输出: 'day01', 'CREATE DATABASE `day01` /*!40100 DEFAULT CHARACTER SET utf8 */' ~~~ ### 2.4 删除数据库: 这条语句勿乱用!!!!!!! 1. 语法格式: ~~~ drop database 数据库名; ~~~ 1. 实践: 删除刚刚创建的数据库; ~~~ mysql> drop database day01; Query OK, 0 rows affected (0.01 sec) ~~~ ### 2.5修改数据库: 1. 语法格式: ~~~ alter database 数据库名 default character set gbk; ~~~ 1. 实践: 修改刚刚创建的数据库的默认字符; ~~~ mysql> alter database day01 default character set gbk; Query OK, 1 row affected (0.00 sec) ~~~ ### 2.6使用数据库 要对一个数据库进行操作, 必须先选择该数据库, 否则会提示错误: ERROR 1046(3D000): No database selected 两种方式对数据库进行使用的选择: 1. 在登录数据库时指定, 命令: mysql -D 所选择的数据库名 -h 主机名 -u 用户名 -p 例如登录时选择刚刚创建的数据库: mysql -D day01 -u root -p; 2. 在登录后使用 use 语句指定, 命令: use 数据库名; use 语句可以不加分号, 执行 use samp_db 来选择刚刚创建的数据库, 选择成功后会提示: Database changed ### 3.表管理: 有了数据库你就可以对数据库进行操作了,比如创建和修改表,添加数据等;下面的演示都以day01来表现; ~~~ use day01;--使用day01 ~~~ ### 3.1查看所有表: 1. 语法格式: ~~~ show tables; ~~~ 1. 演示如下:因为我们还没有创建表所以是空表 ~~~ mysql> show tables; Empty set (0.00 sec) ~~~ ### 3.2创建表 有了数据库必须有表才能存储你所需要的数据; 1. 表能存储的字符类型如下: ~~~ 1.数字类型 整数: tinyint、smallint、mediumint、int、bigint 浮点数: float、double、real、decimal 2.日期和时间: date、time、datetime、timestamp、year 3.字符串类型 字符串: char、varchar 文本: tinytext、text、mediumtext、longtext 4.二进制(可用来存储图片、音乐等): tinyblob、blob、mediumblob、longblob ~~~ 1. 语法格式 ~~~ ##简单格式 create table 表名称(列声明);**注意**列声明由逗号隔开最后一个列声明没有逗号。 ##带条件创建,判断是否存在表:不存在则创建: create table if not exists 表名称(列声明); ~~~ 1. 实践: 以创建 students 表为例, 表中将存放 学号(sid)、姓名(sname)、分数(smark)、年龄(sage)、 这些内容: ~~~ -- create table create table student( sid INT,-- 学号整型 sname varchar(20),-- 名字字符型 smark int,-- 分数整型 sage int-- 年龄 ); ##输出: Query OK, 0 rows affected (0.01 sec) ~~~ 1. 查看刚刚创建的表结构: ~~~ desc student; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | sid | int(11) | YES | | NULL | | | sname | varchar(20) | YES | | NULL | | | smark | int(11) | YES | | NULL | | | sage | int(11) | YES | | NULL | | ~~~ ### 3.3删除表 这条语句勿乱用!!!!!!! 1. 语法格式: ~~~ drop table 表名; ~~~ 1. 实践: 删除刚刚创建表; ~~~ mysql> drop table student; Query OK, 0 rows affected (0.01 sec) ~~~ ### 3.4修改表: 修改用alter命令语句; 1. 添加字段: ~~~ -- 添加字段sgender varchar(2);性别 alter table student add column sgender varchar(2); ~~~ 1. 删除字段: ~~~ -- 删除字段,先添加sbb字段,然后再删除 alter table student add column sbb varchar(2); alter table student drop column sbb; ~~~ 1. 修改字段类型: ~~~ -- 修改字段数据类型。修改字段 smark int到 smark varchar(2); alter table student modify column smark varchar(2); ~~~ 1. 修改字段名称: ~~~ -- 修改字段名称,将smark修改为mark alter table student change column smark mark int; ~~~ 1. 修改表名称: ~~~ -- 修改表名称,将student表名修改为teacher alter table student rename to teacher; ~~~ ### 4.增删改数据 毫无疑问查询语句是sql中用的最多的语句,但是没有增删改,查询的存在也无意义。这部分只要讲解:insert,update,delete语句的使用; ### 4.1插入数据:insert insert语句也是常用语句,用来向表插入一行数据。 1. 语法格式: ~~~ ##插入:全部字段必须给值 INSERT INTO 表名 VALUES(值);-- 此去必须给全值 ##插入部分字段: INSERT INTO 表名(字段1,字段2) VALUES(字段1的值,字段2的值) ~~~ 1. 实践: 向student插入数据: ~~~ -- 1.增加数据 INSERT INTO student VALUES(001,'peace',1,22,'男');-- 注意不能少或多字段值 -- 插入部分字段 INSERT INTO student(sid,sname) VALUES(002,'rong'); ~~~ ### 4.2删除数据:delete delete语句要慎用!!! 1. 语法格式: delete from 表 where 条件(可选) 1. 演示如下: ~~~ -- 删除所有数据(建议少用)-- -- delete from student; -- 带条件的删除-- delete from student where sid=003; ~~~ 1. delete和truncate table比较 ~~~ -- delete from: 可以全表删除 1)可以带条件删除 2)只能删除表的数据,不能删除表的约束 3)使用delete from删除的数据可以回滚(事务) -- truncate table: 可以全表删除 1)不能带条件删除 2)即可以删除表的数据,也可以删除表的约束 3)使用truncate table删除的数据不能回滚 -- TRUNCATE TABLE student; ~~~ ### 4.3修改数据:update 这个可以用来修改指定行的内容,比如qq修改名字等 1. 语法格式: update 表名 set 字段名=修改后的值 where 条件(可选); 1. 演示如下: ~~~ -- 修改所有数据,建议少用-- UPDATE student set mark=10; -- 带条件的修改(建议使用)-- update student set mark=2 where sid=2; -- 修改多个字段,SET 字段名=值,字段名=值,....-- update student set mark=1,sage=23 where sid=1; ~~~ 好的本章介绍到这里 来自一条小鲨鱼wpeace(rlovep.com)
';

操作系统之分页分段介绍

最后更新于:2022-04-01 14:17:27

### 一.虚拟内存的由来 1.问题提出:      当直接让进程使用直接的物理内存时,当对物理内存操作时会出现混乱。比如进程A装在0-30的物理内层,在29处是一条ADD指令。而进程B装在30-40处第一条指令为JMP 29.没有使用虚拟内存的话,进程B将直接跳到进程A从而使两者程序都破坏掉。 2.解决办法:     有两种解决这个问题:一种通过基址寄存器和界线寄存器形成地址空间,通过交换技术解决内存超载。另外一种就是基于分页的虚拟地址技术。      1)交换技术:把一个进程完整调入内存运行一段时间,然后把他存回磁盘,空闲进程主要存储在磁盘上。缺点:当进程空间大于内存时,不能使用。      2)虚拟内存:把一个进程的一部分调入内存中运行,当内存没有空闲空间时,将新的覆盖旧的页,同时将旧 是写入磁盘。虚拟内存主要使用分页存储管理模式。 ### 二.  分页存储管理 **实际上存储在物理内存上(磁盘上),运行时一页一页读取;** 1.基本思想      用户程序的地址空间被划分成若干固定大小的区域,称为“页”,相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配。 1)      等分内存     页式存储管理将内存空间划分成等长的若干物理块,成为物理页面也成为物理块,每个物理块的大小一般取2的整数幂。内存的所有物理块从0开始编号,称作物理页号。 2) 逻辑地址      系统将程序的逻辑空间按照同样大小也划分成若干页面,称为逻辑页面也称为页。程序的各个逻辑页面从0开始依次编号,称作逻辑页号或相对页号。每个页面内从0开始编址,称为页内地址。程序中的逻辑地址由两部分组成:页号P和页内位移量W。 在执行一个程序之前,内存管理器需要的准备工作: 1) 确定程序的页数 2) 在主存中留出足够的空闲页面 3) 将程序的所有页面载入主存里。(静态的分页,页面无需连续) 2. 分页存储管理的地址机构 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001383608.jpg)     页号x位,每个作业最多2的x次方页,页内位移量的位数表示页的大小,若页内位移量y位,则2的y次方,即页的大小,页内地址从000000000000开始到2的y次方 **若给定一个逻辑地址为A,页面大小为L,则** **页号P=INT[A/L],页内地址W=A  MOD  L** 3.内存分配     相邻的页面在内存中不一定相邻,即分配给程序的内存块之间不一定连续。对程序地址空间的分页是系统自动进行的,即对用户是透明的。由于页面尺寸为2的整数次幂,故相对地址中的高位部分即为页号,低位部分为页内地址。 4. 页表       分页系统中,允许将进程的每一页离散地存储在内存的任一物理块中,为了能在内存中找到每个页面对应的物理块,系统为每个进程建立一张页表,用于记录进程逻辑页面与内存物理页面之间的对应关系。页表的作用是实现从页号到物理块号的地址映射,地址空间有多少页,该页表里就登记多少行,且按逻辑页的顺序排列,形如: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001395e54.jpg) [](http://img.bimg.126.net/photo/j1tSYpegOv6Oom1ZzSmIvg==/3113676192374877352.jpg) 5. 地址变换(MMu)       页式虚拟存储系统的逻辑地址是由页号和页内地址两部分组成,地址变换过程如图7-3所示。假定页面的大小为4K,图7-3中所示的十进制逻辑地址8203经过地址变换后,形成的物理地址a应为十进制。 ** **             ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0013acfed.png) 页号: 8203/4096 = 2;页内偏移:8203%4096= 11;物理地址:物理块号*页面大小+ 页内偏移= 28683。 6. 具有快表的地址变换机构      分页系统中,CPU每次要存取一个数据,都要两次访问内存(访问页表、访问实际物理地址)。为提高地址变换速度,增设一个具有并行查询能力的特殊高速缓冲存储器,称为“联想存储器”或“快表”,存放当前访问的页表项。 7.页面的共享与保护     当多个不同进程中需要有相同页面信息时,可以在主存中只保留一个副本,只要让这些进程各自的有关项中指向内存同一块号即可。同时在页表中设置相应的“存取权限”,对不同进程的访问权限进行各种必要的限制。 8.页面置换:      当进程在物理内存中运行时,调用到不在物理内存中的虚拟页面时,MMU注意到该页面没有被映射到物理内存,于是cpu陷入到操作系统,这个陷阱称为缺页中断,操作系统找到一个很少使用的页框且把他的内容写入磁盘备份。随后把需要访问的虚拟页面读到刚才回收的页框中,修改映射关系,然后重新启动引起陷阱的指令。 主要的页面置换算法有: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0013bfd28.jpg) ### 三.分段存储管理 1.基本思想       页面是主存物理空间中划分出来的等长的固定区域。分页方式的优点是页长固定,因而便于构造页表、易于管理,且不存在外碎片。但分页方式的缺点是页长与程序的逻辑大小不相关。例如,某个时刻一个子程序可能有一部分在主存中,另一部分则在辅存中。这不利于编程时的独立性,并给换入换出处理、存储保护和存储共享等操作造成麻烦。       另一种划分可寻址的存储空间的方法称为分段。段是按照程序的自然分界划分的长度可以动态改变的区域。通常,程序员把子程序、操作数和常数等不同类型的数据划分到不同的段中(写c程序时会用到),并且每个程序可以有多个相同类型的段。      段表本身也是一个段,可以存在辅存中,但一般是驻留在主存中。 将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配。 2. 分段地址结构       作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。例程序段、数据段等。每个段都从0开始编址,并采用一段连续的地址空间。段的长度由相应的逻辑信息组的长度决定,因而各段长度不等。整个作业的地址空间是二维的。        在段式虚拟存储系统中,虚拟地址由段号和段内地址组成,虚拟地址到实存地址的变换通过段表来实现。每个程序设置一个段表,段表的每一个表项对应一个段,每个表项至少包括三个字段:有效位(指明该段是否已经调入主存)、段起址(该段在实存中的首地址)和段长(记录该段的实际长度)。 3. 地址变换       针对每一个虚拟地址,存储管理部件首先以段号S为索引访问段表的第S个表项。若该表项的有效位为1,则将虚拟地址的段内地址D与该表项的段长字段比较;若段内地址较大则说明地址越界,将产生地址越界中断;否则,将该表项的段起址与段内地址相加,求得主存实地址并访存。如果该表项的有效位为0,则产生缺页中断,从辅存中调入该页,并修改段表。段式虚拟存储器虚实地址变换过程如图所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0013e752f.jpg) 绝对地址=根据段号找到段表中的起始地址+段内地址 (如果段内地址超过限长则产生“地址越界”程序性中断事件达到存储保护) 4. 分段存储方式的优缺点      分页对程序员而言是不可见的,而分段通常对程序员而言是可见的,因而分段为组织程序和数据提供了方便。与页式虚拟存储器相比,段式虚拟存储器有许多优点: (1)    段的逻辑独立性使其易于编译、管理、修改和保护,也便于多道程序共享。 (2)    段长可以根据需要动态改变,允许自由调度,以便有效利用主存空间。 (3)    方便编程,分段共享,分段保护,动态链接,动态增长  因为段的长度不固定,段式虚拟存储器也有一些缺点: (1)    主存空间分配比较麻烦。 (2)    容易在段间留下许多碎片,造成存储空间利用率降低。 (3)    由于段长不一定是2的整数次幂,因而不能简单地像分页方式那样用虚拟地址和实存地址的最低若干二进制位作为段内地址,并与段号进行直接拼接,必须用加法操作通过段起址与段内地址的求和运算得到物理地址。因此,段式存储管理比页式存储管理方式需要更多的硬件支持。 四.段页式存储 1.  段页式存储管理的基本思想    段页式存储组织是分段式和分页式结合的存储组织方法,这样可充分利用分段管理和分页管理的优点。    (1) 用分段方法来分配和管理虚拟存储器。程序的地址空间按逻辑单位分成基本独立的段,而每一段有自己的段名,再把每段分成固定大小的若干页。      (2) 用分页方法来分配和管理实存。即把整个主存分成与上述页大小相等的存储块,可装入作业的任何一页。程序对内存的调入或调出是按页进行的。但它又可按段实现共享和保护。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0014089a6.jpg)                             地址空间图       (3)    逻辑地址结构。一个逻辑地址用三个参数表示:段号S;页号P;页内地址d。 [](http://photo.blog.sina.com.cn/showpic.html#blogid=5f240fc40100cng9&url=http://s14.sinaimg.cn/orignal/5f240fc4g67333b78a11d) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00141d449.jpg)                          逻辑地址结构  (4)段表、页表、段表地址寄存器。为了进行地址转换,系统为每个作业建立一个段表,并且要为该作业段表中的每一个段建立一个页表。系统中有一个段表地址寄存器来指出作业的段表起始地址和段表长度。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001430337.jpg) 2.地址变换过程    一个逻辑地址为:基地址x、段号s、页号p和页内地址d,求物理地址:(((x)+s)+p)*2^(11)+d                                    ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001446b19.jpg)                                                ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0014643e3.jpg) 在段页式系统中,为了便于实现地址变换,须配置一个段表[寄存器](http://baike.baidu.com/view/6159.htm),其中存放段表始址和段表长TL。     1) 进行地址变换时,首先利用段号S,将它与段表长TL进行比较。若S<TL,表示未越界    2) 于是利用段表始址和段号来求出该段所对应的段表项在段表中的位置,从中得到该段的[页表](http://baike.baidu.com/view/2143270.htm)始址    3) 利用[逻辑地址](http://baike.baidu.com/view/893778.htm)中的段内页号P来获得对应页的页表项位置,从中读出该页所在的物理块号b    4) 再利用块号b和页内地址来构成[物理地址](http://baike.baidu.com/view/883168.htm)。        上图示出了段页式系统中的地址变换机构。在段页式系统中,为了获得一条指令或数据,须三次访问内存。第一次访问是访问内存中的段表,从中取得[页表](http://baike.baidu.com/view/2143270.htm)始址;第二次访问是访问内存中的页表,从中取出该页所在的物理块号,并将该块号与页内地址一起形成指令或数据的[物理地址](http://baike.baidu.com/view/883168.htm);第三次访问才是真正从第二次访问所得的地址中,取出指令或数据。 显然,这使访问内存的次数增加了近两倍。为了提高执行速度,在地址变换机构中增设一个高速缓冲[寄存器](http://baike.baidu.com/view/6159.htm)。每次访问它时,都须同时利用段号和页号去检索[高速缓存](http://baike.baidu.com/view/32390.htm),若找到匹配的表项,便可从中得到相应页的物理块号,用来与页内地址一起形成[物理地址](http://baike.baidu.com/view/883168.htm);若未找到匹配表项,则仍须再三次访问内存。 3.段页式存储管理的优缺点  优点    (1) 它提供了大量的虚拟存储空间。    (2) 能有效地利用主存,为组织多道程序运行提供了方便。 缺点:    (1) 增加了硬件成本、系统的复杂性和管理上的开消。    (2) 存在着系统发生抖动的危险。    (3) 存在着内碎片。    (4) 还有各种表格要占用主存空间。  段页式存储管理技术对当前的大、中型计算机系统来说,算是最通用、最灵活的一种方案。
';

JSP入门之自定义标签

最后更新于:2022-04-01 14:17:25

> 第二部分简单讲解:主要讲解el表达式,核心标签库。本章主要讲解:自定义标签库;404页面,505页面,错误页面配置方法 全部代码下载:[链接](http://download.csdn.net/detail/peace1213/9303561) ### 1.JSP自定义标签: 自定义标签是用户定义的JSP语言元素。当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对被 称为tag handler的对象的操作,即当servlet执行时Web container调用那些操作。JSP标签扩展可以让你创建新的标签并且可以直接插入到一个JSP页面。 JSP 2.0规范中引入Simple Tag Handlers来编写这些自定义标记。你可以继承SimpleTagSupport类并重写的doTag()方法来开发一个最简单的自定义标签。 ### 2.开发自定义标签 下面的步骤建立一个自定义标签用于战术客户端的ip地址: 1. 编写一个普通的java类,继承SimpleTagSupport类 ~~~ public class ShowIp extends SimpleTagSupport { /** * 以下屏蔽的代码在SimpleTagSupport代码中已经做了!这里不需要重复再做! */ /*private JspContext context; *//** * 传入pageContext *//* @Override public void setJspContext(JspContext pc) { this.context = pc; }*/ @Override public void doTag() throws JspException, IOException { PageContext pageContext=(PageContext)this.getJspContext(); ServletRequest request = pageContext.getRequest(); String ip=request.getRemoteHost(); JspWriter out = pageContext.getOut(); out.write("使用自定义标签展示客户ip地址"+ip); List<String> a=null; } } ~~~ 2.在web项目的WEB-INF目录下建立mytaglib.tld文件,这个tld叫标签库的声明文件。(参考核心标签库的tld文件) ~~~ <?xml version="1.0" encoding="UTF-8" ?> <taglib 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-jsptaglibrary_2_1.xsd" version="2.1"> <description>A tag library exercising SimpleTag handlers.</description> <!-- 标签库的版本 --> <tlib-version>1.0</tlib-version> <!-- 标签库前缀 --> <short-name>rlovep</short-name> <!-- tld文件的唯一标记 --> <uri>http://rlovep.com</uri> <!-- 定义标签,标签要放在方法前面 --> <tag> <!-- 标签名 --> <name>showIp</name> <!-- 标签处理类 --> <tag-class>com.rlovep.tags.ShowIp</tag-class> <body-content>empty</body-content> </tag> <tag> </taglib> ~~~ 3.在jsp页面的头部导入自定义标签库:url为你在tld中写的url,前缀也是你在tld文件中定义的 ~~~ <%@ taglib uri="http://rlovep.com" prefix="rlovep" %> ~~~ 4.在jsp中使用自定义标签 ~~~ <%-- 测试简单的自定义标签,标签体(我是你)不显示 --%> <rlovep:showIp>我是你 </rlovep:showIp> ~~~ ### 3.自定义标签的执行过程 当访问:[http://localhost:8080/stuJsp/Hellotags.jsp](http://localhost:8080/stuJsp/Hellotags.jsp) 时;要重启Tomcat使服务器启动时,加载每个web应用的WEB-INF目录下的所有文件!!!例如。web.xml, tld文件!!! 步骤如下: 1. 检查jsp文件的taglib指令,是否存在一个url为[http://rlovep.com](http://rlovep.com)的tld文件。如果没有,则报错。 2. 执行jsp文件的转化:把jsp文件翻译成java源文件->编译class->构造类对象->调用_jspService()方法 3. 读到到mytaglib.tld文件中查询是否存在为showIp的标签 4. 找到对应的标签,则读到内容,得到com.rlovep.tags.ShowIp 5. 构造ShowIp对象,然后调用ShowIp里面的方法:dotag方法; ### 4.访问标签体 你可以像标准标签库一样在标签中包含消息内容。如我们要在我们自定义的中包含内容 1. 格式如下: ~~~ <rlovep:showIp>我是你 </rlovep:showIp> ~~~ 2.但要文字显示需要修改处理类和tld文件: 修改处理类在doTag方法中增加如下内容: ~~~ JspContext jspContext2 = this.getJspContext(); //显示标签体的两种方法 //方法1直接调用 //jspBody.invoke(null); //方法2通过输出到out //jspBody.invoke(jspContext2.getOut()); ~~~ 修改tld文件: ~~~ <tag> <!-- 标签名 --> <name>showIp</name> <!-- 标签处理类 --> <tag-class>com.rlovep.tags.ShowIp</tag-class> <!-- 输出标签体的内容格式标签体不可以写jsp的java代码 --> <body-content>scriptless</body-content> </tag> ~~~ 3.现在你可以将标签体的内容显示了; ~~~ <%-- 标签提会显示 --%> <rlovep:showIp>我是你 </rlovep:showIp> ~~~ 4.输出标签体的内容格式: ~~~ JSP: 在传统标签中使用的。可以写和执行jsp的java代码。 scriptless: 标签体不可以写jsp的java代码 empty: 必须是空标签。 tagdependent : 标签体内容可以写jsp的java代码,但不会执 ~~~ ### 5.给标签体带属性: 你可以在自定义标准中设置各种属性,要接收属性,值自定义标签类必须实现setter方法; 1.格式如下: ~~~ <!-- 测试带属性的标签,标签体显示通过类处理 --> <rlovep:AttributeTags name="peace" value="12345 ~~~ 2.定义属性步骤如下: 编写处理类:AttributeTags extends SimpleTagSupport ~~~ 添加俩个属性: //声明属性的成员变量 private Integer value; private String name; 并为两个成员属性写setter方法; public void setValue(Integer value) public void setName(String name) ~~~ 在标签库文件tld注明此标签和属性: ~~~ <!-- 标签名 --> <name>AttributeTags</name> <!-- 标签处理类 --> <tag-class>com.rlovep.tags.AttributeTags</tag-class> <!-- 输出标签体的内容格式标签体不可以写jsp的java代码 --> <body-content>scriptless</body-content> <!-- 配置属性name --> <attribute> <name>name</name> <!-- 是否必填 --> <required>true</required> <!-- 是否支持EL表达式 --> <rtexprvalue>true</rtexprvalue> </attribute> <!-- 配置属性value --> <attribute> <name>value</name> <!-- 是否必填 --> <required>true</required> <!-- 是否支持EL表达式 --> <rtexprvalue>true</rtexprvalue> </attribute> </tag> ~~~ 3.现在就可以用带属性的标签了 ~~~ <!-- 测试带属性的标签,标签体显示通过类处理 --> <rlovep:AttributeTags name="peace" value="123456"> ~~~ 4.在tld配置属性时你可以配置下面的属性: ![12](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001367883.png "") ### 6.带有子标签的自定义标签: 就像核心标签库的choose标签一样我们也可以定义嵌套的自定义标签,这部分我们主要讲解自己创建一个类似核心标签库的choose标签。步骤如下: 1.建立处理类,处理类还是与前面一样的方法。需要介绍的是用到了一个getParent()方法,从名字上就可以知道是为了获得父标签,对就是获得父标签类; 建立三个处理类文件: ChooseTag,OtherWiseTag,whenTag ~~~ //ChooseTag类: public class ChooseTag extends SimpleTagSupport{ //此去时变量不是标签属性,由when标签更改;othewise获得; private boolean flag; public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } @Override public void doTag() throws JspException, IOException { // Choose标签作用显示标签体,以及作为其他两个标签的父标签; getJspBody().invoke(null); } } //whenTag类 public class whenTag extends SimpleTagSupport{ //增加test属性 private boolean test; public boolean isTest() { return test; } public void setTest(boolean test) { this.test = test; } @Override public void doTag() throws JspException, IOException { //如果标签属性为true,显示标签体 if(test){ getJspBody().invoke(null); } //设置父标签给otherwise用 ChooseTag parent=null; if(getParent() instanceof ChooseTag){ parent=(ChooseTag)getParent(); parent.setFlag(test); } } } //OtherWiseTag类: public class OtherWiseTag extends SimpleTagSupport { @Override public void doTag() throws JspException, IOException { boolean test=true; //获取父标签的test,由他的上一个when设置 if(getParent() instanceof ChooseTag) { //获取父标签的test,由他的上一个when设置 ChooseTag parent=(ChooseTag)getParent(); test=parent.isFlag(); } if(!test){ getJspBody().invoke(null); } } } ~~~ 2.编写tld文件:与其他的标签定义一模一样 ~~~ <!-- 定义标签,choose--> <tag> <!-- 标签名 --> <name>choose</name> <!-- 标签处理类 --> <tag-class>com.rlovep.tags.ChooseTag</tag-class> <!-- 输出标签体的内容格式标签体不可以写jsp的java代码 --> <body-content>scriptless</body-content> </tag> <!-- 定义标签,when--> <tag> <!-- 标签名 when --> <name>When</name> <!-- 标签处理类 --> <tag-class>com.rlovep.tags.whenTag</tag-class> <!-- 输出标签体的内容格式标签体不可以写jsp的java代码 --> <body-content>scriptless</body-content> <!-- 配置属性name --> <attribute> <name>test</name> <!-- 是否必填 --> <required>true</required> <!-- 是否支持EL表达式 --> <rtexprvalue>true</rtexprvalue> </attribute> </tag> <!-- 定义标签,Otherwise--> <tag> <!-- 标签名 --> <name>otherwise</name> <!-- 标签处理类 --> <tag-class>com.rlovep.tags.OtherWiseTag</tag-class> <!-- 输出标签体的内容格式标签体不可以写jsp的java代码 --> <body-content>scriptless</body-content> </tag> ~~~ 3.使用带子标签的标签:与使用其他标签稍微有些不同,需要嵌套 ~~~ <!-- 测试choose --> <rlovep:choose> <rlovep:When test="${10<5 }"> 条件成立执行when </rlovep:When> <rlovep:otherwise> 条件不成立执行otherwise </rlovep:otherwise> </rlovep:choose> ~~~ 自定义标签就介绍到这里; ### 404页面,505页面,错误页面配置方法: 可以在web.xml中给你的网站配置全局的404页面,505页面,错误页面;配置方法如下:记得建立相应的跳转文件。 ~~~ <?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"> <!-- 配置空指针异常 --> <error-page> <exception-type>java.lang.NullPointerException</exception-type> <location>/error.jsp</location> </error-page> <!-- 配置505错误页面 --> <error-page> <error-code>500</error-code> <location>/common/500.jsp</location> </error-page> <!-- 配置404错误页面 --> <error-page> <error-code>404</error-code> <location>/common/404.html</location> </error-page> </web-app> ~~~ 好的本章介绍到这里 JSP入门就介绍到这里,哟哟,切割闹; 来自一条小鲨鱼wpeace(rlovep.com)
';

JSP入门实战下

最后更新于:2022-04-01 14:17:23

> 第一部分简单讲解:jsp语法的规范,以及三大编译指令,七个动作指令和九大内置对象,生命周期讲解等。这章主要讲解el表达式,核心标签库。 全部代码下载:[链接](http://download.csdn.net/detail/peace1213/9303561) ### 1.核心标签库(JSTL:c)讲解: ### 1.1简要介绍: JSTL全名JspServer Pages Standdard Tag Library(Jsp标准标签库),它是sun公司发布的一个针对JSP开发的新组件,它允许使用标签开发Jsp页面.JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。 JSTL所提供的标签库主要分为五大类: ![09](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00131bec0.png "") ### 1.2JSTL库安装: 1. 从Apache的标准标签库中下载的二进包(jakarta-taglibs-standard-current.zip)。下载地址:[http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/](http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/) 1. 将下载的压缩包解压,将lib下的两个jar文件:standard.jar和jstl.jar文件拷贝到Tomcat下lib/目录下。 1. 现在就可以通过在头部包含标签使用JSTL了 ### 1.3核心标签库的使用: 核心标签是最常用的JSTL标签。现在基本上我们也之使用功能核心标签库,此去只介绍核心标签,对于其他的标签用法类似。 1. 引用核心标签库的语法如下: ~~~ <%--导入核心标签库 --%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" ~~~ 1. 核心标签库的介绍: ![10](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001333b69.png "") 1. 演示如下:详细见注释 ~~~ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*,com.rlovep.entity.Student" %> <%--导入核心标签库 --%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>核心标签jiangjie</title> </head> <body> <%--使用标签库 --%> <%--set标签:保存数据到域中,默认保存到pag域中 var:属性名 value:属性价值,可以是对象 scope:范围 --%> <c:set var="name" value="rose" scope="page"></c:set> <%--out标签: 类似输出表达式:<%= %> value:显示的内容; default:value为空时显示的内容 escapexml:是否对<等实体符号转义; --%> <%--el表达式输出,调用属性 --%> <c:out value="${name }" default="<h3>标题3</h3>" escapeXml="true"></c:out> <%--默认值测试,以及输出特殊字符 --%> <c:out value="${peace }" default="<h3>标题</h3>" escapeXml="true"></c:out> <hr/> <%--remove标签:删除数据,默认删除到pag域中 var:属性名 scope:范围 --%> <c:remove var="name" scope="page"/> <c:out value="${name }" default="删除name之后" escapeXml="true"></c:out> <hr/> <%--catch标签:可以用来取得发生错误时的信息,同时可以进行适当处理.相当于try catch var:保存错误信息的exception --%> <c:catch var="e"> <% int a=0,b=10; b=b/a; %> </c:catch> <%--输出错误信息 --%> <c:out value="${e }"/> <%-- <% int a=0,b=10; b=b/a; %> --%> <hr/> <%-- <c:url>标签将URL格式化为一个字符串,然后存储在一个变量中 var:变量名。 value:url context:本地的另一个工程库 --%> <%--c:param 在重定向时当参数用 --%> <c:url var="url" value="el.jsp"> <c:param name="pass" value="peace"/> </c:url> <a href="${url }">url重定向</a> <c:url var="baidu" value="http://wwww.baidu.com"/> <a href="${baidu }">百度</a> <hr/> <%--<c:import>标签:功能类似于<jsp:import>,但是功能更加强大。可以导入外部jsp文件,和保存到输入流中 var:输出保存到string varReader:输出保存到输入字符流 url:包含的页面 --%> <c:import url="/common/header1.jsp" > <c:param name="name" value="sisi"/> </c:import> <hr/> <%--c:redirect 标签 可以是绝对地址 url:地址 context:另外一个jsp容器 --%> <%-- <c:redirect url="el.jsp"> <c:param name="pass" value="wang"></c:param> </c:redirect> --%> <% Integer score=new Integer(60); pageContext.setAttribute("score", score); %> <%--if标签 :单条件判断 test:判断是否为true执行 --%> <c:if test="${!empty score}"> 条件成立 </c:if> <hr/> <%--choose标签+when标签+otherwirse标签: 多条件判断 --%> <c:set var="score" value="56"></c:set> <c:choose> <c:when test="${score>=90 && score<=100}"> 优秀 </c:when> <c:when test="${score>=80 && score<90}"> 良好 </c:when> <c:when test="${score>=70 && score<80}"> 一般 </c:when> <c:when test="${score>=60 && score<70}"> 及格 </c:when> <c:otherwise> 不及格 </c:otherwise> </c:choose> <%-- forEach标签:循环 --%> <% //List List<Student> list = new ArrayList<Student>(); list.add(new Student("rose",18)); list.add(new Student("jack",28)); list.add(new Student("lucy",38)); //放入域中 pageContext.setAttribute("list",list); //Map Map<String,Student> map = new HashMap<String,Student>(); map.put("100",new Student("mark",20)); map.put("101",new Student("maxwell",30)); map.put("102",new Student("narci",40)); //放入域中 pageContext.setAttribute("map",map); %> <hr/> <%-- begin="" : 从哪个元素开始遍历,从0开始.默认从0开始 end="": 到哪个元素结束。默认到最后一个元素 step="" : 步长 (每次加几) ,默认1 items="": 需要遍历的数据(集合) var="": 每个元素的名称 varStatus="": 当前正在遍历元素的状态对象。(count属性:当前位置,从1开始,last属性:最后一个) --%> <c:forEach items="${list}" var="student" varStatus="varSta"> 序号: {student.name } - 年龄:${student.age}<br/> </c:forEach> <hr/> <c:forEach items="${map}" var="entry"> {entry.value.name } - 年龄:${entry.value.age }<br/> </c:forEach> <hr/> <%-- forToken标签: 循环特殊字符串 --%> <% String str = "java-php-net-平面"; pageContext.setAttribute("str",str); %> <c:forTokens items="${str}" delims="-" var="s" varStatus="status"> ${s }<br/> <c:if test="${status.last }"> <c:out value="输出:${status.count}"/>个元素 </c:if> </c:forTokens> </body> </html> ~~~ ### 2.EL表达式语言: E L(Expression Language) 目的:为了使JSP写起来更加简单。 EL 提供了在 JSP 脚本编制元素范围外使用运行时表达式的功能。 EL既可以用来创建算术表达式也可以用来创建逻辑表达式。在JSP EL表达式内可以使用整型数,浮点数,字符串,常量true、false,还有null。 EL使得访问存储在JavaBean中的数据变得非常简单,EL可以访问内置对象,以及放置在对象中的属性; EL表达式作用: 向浏览器输出域对象中的变量值或表达式计算的结果!!! ### 2.1EL语法:${exper} 1. 输出基本数据类型变量: 不注明域的范围时,从四个域中获取:顺序为pageScoep / requestScope / sessionScope / applicationScope name<指定域获取:{pageScope.name} <%–等价于getAttribute()方法;–%> 1. 输出对象的属性值 ${student.name} 等价于 (点相对于调用getXX()方法) 1. 使用EL获取集合对象 {list[0].age } <%– list[0]等价于 (中括号相对于调用get(参数)方法) ((List)pageContext.findAttribute(“list”)).get(0)–%> 1. el还可以执行算法表达式 EL表达式支持大部分Java所提供的算术和逻辑操作符: ![11](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0013512bc.png "") 演示如下: ~~~ 比较运算 ${10>5 }<br/> ${10<5 }<br/> ${10!=10 } <hr/> 逻辑运算 ${true && false }<br/> ${true || false }<br/> ${!false }<br/> 判空 null 或 空字符串: empty <% //String name = "eric"; //String name = null; String name = ""; pageContext.setAttribute("name",name); %> 判断null: ${name==null }<br/> 判断空字符: ${name=="" }<br/> 判空: ${name==null || name=="" } 另一种判空写法: ${empty name } ~~~ ### 2.2EL高级用法自定义函数: el表达语言的自定义函数 本质是为了调用提供一种方法允许el中调用某类的静态方法: 1. 自定义函数使用语法: ${rlovep:reverse(student.name)}<%–调用reverse方法使传入的student.name反转–%> 2. 开发步骤: 1.在src建立开发处理类,这个类包含若干个静态方法。当然这个步骤可以省掉使用jdk库的类也是可以的 2.使用标签库定义函数:定义函数的方式与定义标签的方式相似。增加function标签就行; 3.使用:增加taglib指令 3. 演示如下 建立开发处理类: MyFuns.java ~~~ public static String reverse(String str) { return new StringBuffer(str).reverse().toString(); } public static int count(String str) { return str.length(); } ~~~ 在webcontent目录下建立:mytaglib.tld标签库文件,增加function标签 ~~~ <?xml version="1.0" encoding="UTF-8" ?> <taglib 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-jsptaglibrary_2_1.xsd" version="2.1"> <description>A tag library exercising SimpleTag handlers.</description> <!-- 标签库的版本 --> <tlib-version>1.0</tlib-version> <!-- 标签库前缀 --> <short-name>rlovep</short-name> <!-- tld文件的唯一标记 --> <uri>http://rlovep.com</uri> <!-- 定义第一个方法 --> <function> <!-- 定义方法名 --> <name>reverse</name> <!-- 定义方法的处理类 --> <function-class>com.rlovep.elmethod.MyFuns</function-class> <!-- 定义函数的实现方法:包括返回值和函数名以及参数 --> <function-signature>java.lang.String reverse(java.lang.String)</function-signature> </function> <!-- 定义第二个方法 --> <function> <!-- 定义方法名 --> <name>count</name> <!-- 定义方法的处理类 --> <function-class>com.rlovep.elmethod.MyFuns</function-class> <!-- 定义函数的实现方法:包括返回值和函数名以及参数 --> <function-signature>int count(java.lang.String)</function-signature> </function> </taglib> ~~~ 增加taglib指令 <%@taglib prefix=”rlovep” uri=”http://rlovep.com” %> ### 2.3整体演示如下: ~~~ <%@page import="java.util.HashMap,java.util.Map"%> <%@page import="java.util.ArrayList"%> <%@page import="java.util.List"%> <%@page import="com.rlovep.entity.Student"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- 定义标签 --> <%@taglib prefix="rlovep" uri="http://rlovep.com" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>el表达式学习:</title> </head> <body> <%--el的内置对象 --%> <% pageContext.setAttribute("name", "peace"); pageContext.setAttribute("age", "22", pageContext.APPLICATION_SCOPE); %> <%--直接从域中搜索获得属性 --%> El表达式:${name } <hr/> <%--等价于 --%> 表达式:<%=pageContext.findAttribute("name") %> <hr/> <%--从指定域中获取属性 --%> EL表达式:${applicationScope.age} <hr/> <%--等价于 --%> <%=pageContext.getAttribute("age", pageContext.APPLICATION_SCOPE) %> <hr/> <%--获取请求参数 --%> 请求参数${param.pass} <hr/> <%--请求头获取 --%> 请求头${header.Host} <%--还可以获得初始参数:initparam 以及cookie --%> <hr/> <%--el输出对象的属性 ,必须将对象放入域中--%> <% Student student=new Student("peace",22); String a="123"; //放入域中 pageContext.setAttribute("student", student); //放入list中 List<Student> list=new ArrayList<Student>(); list.add(new Student("sisi",22)); list.add(new Student("nick",20)); list.add(new Student("lucy",38)); pageContext.setAttribute("list", list); //放入map中 Map<String,Student> map=new HashMap<String,Student>(); map.put("100",new Student("mark",20)); map.put("101",new Student("maxwell",30)); map.put("102",new Student("narci",40)); //放入域中 pageContext.setAttribute("map",map); %> <%--使用el获取对象值 --%> {student.age } <%-- ${student.name} 等价于 (点相对于调用getXX()方法) <%=((Student)pageContext.findAttribute("student")).getName()%> --%> <hr/> <%--使用EL获取List对象 --%> {list[0].age }<br/> {list[1].age }<br/> {list[2].age } <%-- list[0]等价于 (中括号相对于调用get(参数)方法) ((List)pageContext.findAttribute("list")).get(0) --%> <hr/> <%--使用EL获取Map对象 --%> {map['100'].age }<br/> {map['101'].age }<br/> {map['102'].age }<br/> <%--el还可以执行算法表达式 --%> <%--el表达语言的自定义函数 本质是为了调用提供一种方法允许el中调用某类的静态方法: 1.在src建立开发处理类,这个类包含若干个静态方法。当然这个步骤可以省掉使用jdk库的类也是可以的 2.使用标签库定义函数:定义函数的方式与定义标签的方式相似。增加function标签就行; 3.增加taglib指令 --%> 此去表达式调用函数:<br/> peace倒转:${rlovep:reverse(student.name)}<%--调用reverse方法使传入的student.name反转--%> <br/> peace字符个数:${rlovep:count(student.name)} </body> </html> ~~~ 来自一条小鲨鱼wpeace(rlovep.com)
';

Jsp入门实战上

最后更新于:2022-04-01 14:17:20

> 前面讲了servlet入门实践现在开始介绍jsp入门实践,开发环境的搭建请参考我前面的tomcat的文章,jsp入门教程分为上下两部分,第一部分简单讲解:jsp语法的规范,以及三大编译指令,七个动作指令和九大内置对象,生命周期讲解等。 全部代码下载:[链接](http://download.csdn.net/detail/peace1213/9303561) ### 1.jsp简介: JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它[1] 是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传统的网页HTML(标准通用标记语言的子集)文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。 **第一个jsp程序:** 1. 在eclipse中建立动态web工程 2. 在WebContent上右击建立jsp文件 3. 在jsp文件中输入如下: ~~~ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% out.print("hello peace"); %> </body> </html> ~~~ 1. 在浏览器中输入如下:[http://localhost:8080/](http://localhost:8080/)工程名/NewFile.jsp 显示如下: ![01](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001229769.png "") 1. JSP作为servlet的变体,jsp的文件会被翻译成servlet文件:文件位置为Tomcat按住给你目录:apache-tomcat-7.0.64/work/Catalina/localhost/stuJsp/org/apache/jsp ![02](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00123ed5f.png "") 打开java文件可以看到该文件根servlet的文件类似:有_jspInit(),jspDestroy(),_jspService()方法。并将jsp文件中的代码生成了_jspService()方法中的代码 ![03](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0012528f7.png "") ### 2.JSP语法: #### 2.1.JSP脚本:     脚本程序,就是为了在HTML中穿插java代码,可以包含任意语法真确的java语句,变量,方法或表达式。生成servlet源码时该处的代码被放到_jspService()方法中 1. 脚本程序的语法: <% 代码片段 %> 就像第一个jsp程序那样 ~~~ <% out.print("hello peace"); %> ~~~ 1. **注意**:脚本中不能出现标签和jsp元素,记住只能写java就行;但是可以穿插写:如下: ~~~ <% for(int i=0;i<5;i++) { out.print("hello peace"+i); %> <br/> <% out.print("换行符穿插在中间了,一样会被循环输出"); }//for循环结束 %> ~~~ #### 2.2.JSP声明:     一个声明语句可以声明一个或多个变量、方法,供后面的Java代码使用。在JSP文件中,您必须先声明这些变量和方法然后才能使用它们。生成servlet源码时该处的代码成为类的属性和方法; 1. JSP声明的语法: <%! declaration; [ declaration; ]+ … %> 2. 演示如下: ~~~ <%! private int i=10; %> <%! public void test(){ int a=0; int b=2; a=a+b; System.out.print(a); } %> ~~~ 1. 查看生成的servlet文件可以知道刚才在jsp声明的变量和方法,成为了相应的属性和方法 #### 2.3JSP表达式:     一个JSP表达式中包含的脚本语言表达式,先被转化成String,然后插入到表达式出现的地方,作用相当于脚本中的out(输出) 由于表达式的值会被转化成String,所以您可以在一个文本行中使用表达式而不用去管它是否是HTML标签。 表达式元素中可以包含任何符合Java语言规范的表达式,但是不能使用分号来结束表达式。 生成servlet源码时该处的代码被放到_jspService()方法中 1. JSP表达式的语法格式 <%= 表达式 %> 2. 演示如下: ~~~ <%--在脚本处声明的变量是局部变量不能带有修饰符 --%> <% String nick="sisi"; int a=10,b=10; %> 3.jsp表达式:<br/> <%--表达式可以输出相当于out.write 不需要分号结束--%> <%=(a-b) %> <%=nick %> <hr/> ~~~ #### 2.4JSP注释:     JSP注释不会出现在html的源码中 可以用来注释jsp的代码,html注释会出现在html的源码中; 1. JSP注释的语法格式: <%– 这里可以填写 JSP 注释 –%> 2. 演示如下: ~~~ 1.jsp注释:<br/> <%-- 这些注释不会出现在html的源码中 可以用来注释jsp的代码--%> ~~~ ### 3.三大编译指令: JSP编译指令用来设置与整个JSP页面相关的属性; 主要有三大编译指令: ~~~ <%@ page ... %> 定义页面的依赖属性,比如脚本语言、error页面、缓存需求等等 <%@ include ... %> 包含其他文件 <%@ taglib ... %> 引入标签库的定义,可以是自定义标签 ~~~ ### 3.1page指令介绍: Page指令为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令。 1. Page指令的语法格式: <%@ page attribute=”value” %> 2. 属性: ![04](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00127c6db.png "") 3. 演示如下: ~~~ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.Random"%> ~~~ ### 3.2include指令介绍:(静态包含) JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。 1. Include指令的语法格式如下: <%@ include file=”url” %> 2. Include指令中的文件名实际上是一个相对的URL。如果您没有给文件关联一个路径,JSP编译器默认在当前路径下寻找。 3. 演示如下: ~~~ <%-- 1.原理是把被包含的页面(header.jsp) 的内容翻译到包含页面(index.jsp)中,合并成翻译成一个java源文件, 再编译运行!!,这种包含叫静态包含(源码包含) 2.被包含页面中不需要出现全局的html标签了!!! (如html、head、body)--%> <%@include file="/common/header.jsp"%> ~~~ ### 3.3taglib指令介绍: JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合。Taglib指令引入一个自定义标签集合的定义,包括库路径、自定义标签。 1. taglib指令的语法: <%@ taglib uri=”uri” prefix=”prefixOfTag” %> 2. uri为属性确定的标签位置,prefix属性指定标签库的前缀。此处后面会进一步介绍; 3. 演示如下: ~~~ 自己定义的标签库 <%@ taglib uri="http://rlovep.com" prefix="rlovep" %> ~~~ ### 4.七大动作指令介绍: 动作指令与编译指令不同,编译指令时通知servlet引擎的处理消息,而动作指令只是运行时的动作。编译指令在将JSP编译成Servlet时起作用,而处理指令通常可替换成JSP脚本,它只是JSP脚本的标准化写法。 (1)JSP:forward 执行页面转向,将请求的处理转发到下一个页面。 (2)JSP:param 用于传递参数,必须与其他支持参数的标签一起使用 (3)JSP:include 用于动态引入一个JSP页面 (4)JSP:plugin 用于下载JavaBean或者Applet到客户端执行 (5) JSP:useBean 创建一个Javabean实例 (6) JSP:setProperty 设置JavaBean实例的属性值 (7)JSP:getProperty 获取JavaBean实例的属性值 ### 4.1jsp:forward指令  jsp:forward动作把请求转到另外的页面。jsp:forward标记只有一个属性page。 1. 语法格式如下所示: 2. page属性:page属性包含的是一个相对URL。page的值既可以直接给出,也可以在请求的时候动态计算,可以是一个JSP页面或者一个 Java Servlet. 3. 执行forward指令时,用户请求的地址依然没有发生改变,仍然是一次请求,但页面内容完全变为被forward目标页的内容。执行forward指令转发请求时,客户端的请求参数不会丢失。类似于servlet中的 getRequestDispatcher(“/GetData”).forward(request, response); 4. 可以附带增加额外的请求参数:配合JSP:param动作指令 ~~~ <%--转发 jsp:foward 参数 jsp:param <jsp:forward page="/action2.jsp"> <jsp:param value="peace" name="name"/> <jsp:param value="123456" name="pass"/> </jsp:forward> --%> ~~~ ### 4.2jsp:include指令(动态包含) jsp:include>动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面 1. 语法格式如下: 2. 前面介绍过include的编译指令与前面不同的是这里的是动态包含,静态包含是在JSP文件被转换成Servlet的时候引入文件,而这里的jsp:include动作不同,插入文件的时间是在页面被请求的时候。如果被包含的页面是jsp一样会另一个生成servlet; 3. 属性介绍: page:被包含页面的url flush:布尔属性,定义在包含资源前是否刷新缓存区。 4. 可以附带增加额外的请求参数:配合JSP:param动作指令 ~~~ <%--动态包括 --%> 动态包括: <jsp:include page="/common/header1.jsp"> <jsp:param value="lucc" name="name"/> </jsp:include> ~~~ ![05](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00129aae4.png "") ### 4.3jsp:userBean,setProperty,getProperty指令 这三个指令都是与JavaBean相关的指令,其中userBean指令用于在JSP页面中初始化一个java实例,setProperty指令用于为JavaBean实例的属性设置值;getProperty指令用于输出JavaBean实例的属性。 1. jsp:useBean动作简单的语法为: 其中,id属性是JavaBean的实例名,class属性确定JavaBean的实现类。scope属性用于指定JavaBean实例的作用范围。 2. jsp:setProperty的语法格式: 其中,name属性是要确定JavaBean的实例名,property属性要确定设置属性的属性名,value属性时要确定属性名对应的值。 3. jsp:getProperty的语法格式: 其中,name属性时要确定JavaBean的实例名,name属性是指定要获取的属性名对应的值。 4. 演示如下: ~~~ <%--useBean setProperty getProperty --%> <%--创建Student的实例 实例名称为student 属性范围为page --%> <hr/> <jsp:useBean id="student" class="com.rlovep.entity.Student" scope="page"/> <%--设置student的name值 --%> <jsp:setProperty name="student" property="name" value="peace"/> <%--输出 student的name值--%> name:<jsp:getProperty name="student" property="name" /> ~~~ ### 4.3jsp:param,plugin指令 param用于设置参数值,这个指令本身不能单独使用,因此单独的param指令没有实际意义,param指令可以与以下指令结合使用 jsp:include jsp:forward jsp:plugin。使用方法上面已经介绍; plugin指令主要用于下载服务器端的JavaBean或Applet到到客户端执行,由于程序在客户端执行,因此客户端必须安装虚拟机。该指令用处较少,不做介绍; ### 4.4整体演示如下: 需要建立,action.jsp本文件,以级转发页面action2.jsp,被包含页面/common/header1.jsp,JavaBean:Student类 ~~~ <%--转发 jsp:foward 参数 jsp:param <jsp:forward page="/action2.jsp"> <jsp:param value="peace" name="name"/> <jsp:param value="123456" name="pass"/> </jsp:forward> --%> <%--动态包括 --%> 动态包括: <jsp:include page="/common/header1.jsp"> <jsp:param value="lucc" name="name"/> </jsp:include> <%--useBean setProperty getProperty --%> <%--创建Student的实例 实例名称为student 属性范围为page --%> <hr/> <jsp:useBean id="student" class="com.rlovep.entity.Student" scope="page"/> <%--设置student的name值 --%> <jsp:setProperty name="student" property="name" value="peace"/> <%--输出 student的name值--%> name:<jsp:getProperty name="student" property="name" /> ~~~ ### 5. 9大内置对象介绍 JSP脚本中包含9个内置对象,这9个内置对象都是Servlet API接口的实例,只是JSP规范对他们默认进行了初始化(由JSP页面对应的Servlet的_jspService()方法来创建这些实例)。也就是它们已经是对象,可以直接使用。 ![06](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0012b5bdc.png "") JSP初始化该9个对象的地方可以通过生成的servlet类看到如下: ![07](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0012d87b1.png "") request、response两个对象是_jspService()方法的形参,当Tomcat调用该方法时会初始化这两个对象。而page、pageContext、application、config、session、out都是_jspService()方法的局部变量,由该方法完成初始化。 ### 5.1稍简单再介绍:详细介绍可以观看我的[Servlet入门实践](http://rlovep.com/2015/10/21/Servlet%E5%85%A5%E9%97%A8%E5%AE%9E%E8%B7%B5/) 1. application:javax.servlet.ServletContext的实例,该实例代表JSP所属的Web应用本身,可用于JSP页面,或者在Servlet之间交换信息。常用的方法有getAttribute(StringattName)、setAttribute(String attName , String attValue)和getInitParameter(StringparamName)等。 1. config:javax.servlet.ServletConfig的实例,该实例代表该JSP的配置信息。常用的方法有getInitParameter(StringparamName)和getInitParameternames()等方法。事实上,JSP页面通常无须配置,也就不存在配置信息。因此,该对象更多地在Servlet中有效。 1. exception:java.lang.Throwable的实例,该实例代表其他页面中的异常和错误。只有当页面是错误处理页面,即编译指令page的isErrorPage属性为true时,该对象才可以使用。常用的方法有getMessage()和printStackTrace()等。 1. out:javax.servlet.jsp.JspWriter的实例,该实例代表JSP页面的输出流,用于输出内容,形成HTML页面。 1. page:代表该页面本身,通常没有太大用处。也就是Servlet中的this,其类型就是生成的Servlet类,能用page的地方就可用this。 1. pageContext:javax.servlet.jsp.PageContext的实例,该对象代表该JSP页面上下文,使用该对象可以访问页面中的共享数据。常用的方法有getServletContext()和getServletConfig()等。这个对象存储了request对象和response对象的引用。application对象,config对象,session对象,out对象可以通过访问这个对象的属性来导出。PageContext类定义了一些字段,包括PAGE_SCOPE,REQUEST_SCOPE,SESSION_SCOPE, APPLICATION_SCOPE。它也提供了40余种方法,有一半继承自javax.servlet.jsp.JspContext 类。其中一个重要的方法就是removeArribute(),它可接受一个或两个参数。比如,pageContext.removeArribute(“attrName”)移除四个scope中相关属性,但是下面这种方法只移除特定scope中的相关属性: pageContext.removeAttribute(“attrName”, PAGE_SCOPE); 1. request:javax.servlet.http.HttpServletRequest的实例,该对象封装了一次请求,客户端的请求参数都被封装在该对象里。这是一个常用的对象,获取客户端请求参数必须使用该对象。常用的方法有getParameter(String paramName)、getParameterValues(StringparamName)、setAttribute(String 8. 8/ attrName,Object attrValue)、getAttribute(StringattrName)和setCharacterEncoding(String env)等。 1. response:javax.servlet.http.HttpServletResponse的实例,代表服务器对客户端的响应。通常很少使用该对象直接响应,而是使用out对象,除非需要生成非字符响应。而response对象常用于重定向,常用的方法有getOutputStream()、sendRedirect(java.lang.String location)等。 1. session:javax.servlet.http.HttpSession的实例,该对象代表一次会话。当客户端浏览器与站点建立连接时,会话开始;当客户端关闭浏览器时,会话结束。常用的方法有:getAttribute(String attrName)、setAttribute(StringattrName, Object attrValue)等。 ### 5.2四个域对象: 1. 四个域对象: pageContext——– page域 request ——– request域 session——– session域 application ——–context域 1. 域对象作用: 保存数据 和 获取数据 ,用于数据共享。 1. 域对象方法: setAttribute(“name”,Object) 保存数据 getAttribute(“name”) 获取数据 removeAttribute(“name”) 清除数据 1. 域对象作用范围: page域: 只能在当前jsp页面中使用(当前页面) request域: 只能在同一个请求中使用(转发) session域: 只能在同一个会话(session对象)中使用(私有的) context域: 只能在同一个web应用中使用。(全局的) ### 5.3 整体演示如下: ~~~ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%--out对象:对应jspwriter --%> <% /* for(int i=0;i<=1024;i++){ out.write("a"); } System.out.println("当前缓存区大小:"+out.getBufferSize()); System.out.println("剩余缓存区大小:"+out.getRemaining()); */ //如果不刷新则,123先输出; //out.flush(); response.getWriter().write("123"); %> <%-- application对象:对应servlet中的context 存储的属性,是整个应用共享的;同样可以获得配置参数; --%> <% //存储属性 application.setAttribute("name", "peace"); %> <%=application.getInitParameter("keys") %> <%-- config对象:对应servlet中的config 用处不是很大 --%> <%=config.getServletName() %> <%-- exception对象:在错误页面中有效,可以获得异常属性 亲发生错误:该对象只有当编译指令page的isErrorPage="true"才有效 <%=exception.getMessage() %> --%> <%-- request对象:对应servlet中的request --%> <%=request.getLocalName() %> <%-- response对象:对应servlet中的response --%> <% response.getWriter().println("hello respose"); %> <%-- session对象:对应servlet中的session --%> <% session.setAttribute("pass", "567"); %> <%-- pagecontext对象:jsp的页面对象 可以获得其他八个对象: --%> <% //获得其他对象 response.getWriter().write("是否相等?"+(out==pageContext.getOut())+"<br/>"); %> <%--可以往不同的域中存对象 --%> <% pageContext.setAttribute("message", "wang"); pageContext.setAttribute("age", "22", PageContext.REQUEST_SCOPE); pageContext.setAttribute("qq", "374126165", pageContext.SESSION_SCOPE); pageContext.setAttribute("tl","1881679",pageContext.APPLICATION_SCOPE); //重定向到另一个页面取得数据: response.sendRedirect(request.getContextPath()+"/pageget.jsp"); //删除存储的对象 pageContext.removeAttribute("age",PageContext.REQUEST_SCOPE ); %> </body> </html> ~~~ ### 6.JSP生命周期讲解: 理解JSP底层功能的关键就是去理解它们所遵守的生命周期。JSP生命周期就是从创建到销毁的整个过程,类似于servlet生命周期,区别在于JSP生命周期还包括将JSP文件编译成servlet。 ### 6.1JSP执行过程: 访问:[http://localhost:8080/](http://localhost:8080/)工程名/NewFile.jsp 1. 访问到NewFile.jsp页面,tomcat扫描到jsp文件,在/work/Catalina/localhost/stuJsp/org/apache/jsp把jsp文件翻译成java源文件 (NewFile.jsp -> NewFile_jsp.java) (翻译) 2. tomcat服务器把java源文件编译成class字节码文件 (编译) (NewFile_jsp.java ->NewFile_jsp.class) 3. tomcat服务器构造NewFile_jsp类对象 4. tomcat服务器调用NewFile_jsp类里面方法,返回内容显示到浏览器。 第一次访问jsp:走(1)(2)(3)(4) 之后的访问:走(4) **注意**:jsp文件修改了或jsp的临时文件被删除了,要重新走翻译(1)和编译(2)的过程 ### 6.2JSP生命周期: 1. JSP编译: 当浏览器请求JSP页面时,JSP引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个JSP文件。编译为servlet; 1. JSP初始化: 容器载入JSP文件后,它会在为请求提供任何服务前调用jspInit()方法。你可以重写该方法:在jsp声明段 ~~~ <%! public void jspInit(){ initVar++; System.out.println("jspInit(): JSP被初始化了"+initVar+"次"); } %> ~~~ 1. JSP执行: 这一阶段描述了JSP生命周期中一切与请求相关的交互行为,直到被销毁。每一次服务请求都会执行_jspService()方法。 1. JSP清理: JSP生命周期的销毁阶段描述了当一个JSP网页从容器中被移除时所发生的一切,一般只有在容器停止部署该工程才执行:jspDestroy()方法 你可以进行重写 ~~~ <%! public void jspDestroy(){ destroyVar++; System.out.println("jspDestroy(): JSP被销毁了"+destroyVar+"次"); } %> ~~~ 1. JSP与servlet的生命周期对比 ~~~ Servlet的生命周期: 1)构造方法(第1次访问) 2)init方法(第1次访问) 3)service方法 4)destroy方法 Jsp的生命周期: 1)翻译: jsp->java文件 2)编译: java文件->class文件(servlet程序) 3)构造方法(第1次访问) 4)init方法(第1次访问):_jspInit() 5)service方法:_jspService() 6)destroy方法:_jspDestroy() ~~~ ### 6.3演示如下: ~~~ <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <%! //记录执行次数: private int initVar=0; private int serviceVar=0; private int destroyVar=0; %> <%! public void jspInit(){ initVar++; System.out.println("jspInit(): JSP被初始化了"+initVar+"次"); } public void jspDestroy(){ destroyVar++; System.out.println("jspDestroy(): JSP被销毁了"+destroyVar+"次"); } %> <% serviceVar++;// System.out.println("_jspService(): JSP共响应了"+serviceVar+"次请求"); //对各个的执行次数计数 String content1="初始化次数 : "+initVar; String content2="响应客户请求次数 : "+serviceVar; String content3="销毁次数 : "+destroyVar; %> <%-- 输出显示 --%> <h1><%=content1 %></h1> <h1><%=content2 %></h1> <h1><%=content3 %></h1> </body> </html> ~~~ 显示如下: ![08](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001300821.png "") 来自一条小鲨鱼wpeace(rlovep.com)
';

Servlet入门实践

最后更新于:2022-04-01 14:17:17

> 本文主要介绍servlet,包括入门到升入,基本上可以对servlet有一个很好的认识; ### 1servlet介绍:   Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。 **手把手教你建立一个继承servlet的类:** 1. 在webcontent点击右键选择other,选择servlet,这里就建成了servlet的类 2. 重写doGet和doPost方法 ~~~ public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); out.println("hello peace"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } ~~~ 1. 修改web.xml或者加上webServlet注解: 修改web.xml:在根标签下加入一下代码 ~~~ <!-- 配置一个servlet --> <!-- servlet的配置 --> <servlet> <!-- servlet的内部名称,自定义。尽量有意义 --> <servlet-name>TestServlet</servlet-name> <!-- servlet的类全名: 包名+简单类名 --> <servlet-class>com.rlovep.servlet.TestServlet</servlet-class> <!-- servlet的映射配置 --> </servlet> <servlet-mapping> <!-- servlet的内部名称,一定要和上面的内部名称保持一致!! --> <servlet-name>TestServlet</servlet-name> <!-- servlet的映射路径(访问servlet的名称) --> <url-pattern>/TestServlet</url-pattern> </servlet-mapping> ~~~ **或者在类定义上加上webServlet的注解(注意两者只能有一个)** 注意:1.不要在web.xml根标签中指定metadata-complete=”true”.2。不要在web.xml中配置servlet **修改后的servlet类:** ~~~ @WebServlet("/TestServlet")//设置servlet的访问路径为/TestServlet;或者这样写@WebServlet(name="TestServlet",urlPatterns={"/TestServlet"}) public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); out.println("hello peace"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } ~~~ 1. 访问[http://localhost:8080/HttpSer/TestServlet](http://localhost:8080/HttpSer/TestServlet)即可看到结果。 ### 2servlet的路径映射: ~~~ <url-pattern>/TestServlet</url-pattern>或者:@WebServlet(urlPatterns={"/TestServlet"}) ~~~ <table border="1"><tbody><tr><td>匹配方式</td> <td>url-pattern</td> <td>地址栏</td> </tr><tr><td>精确匹配</td> <td>/TestServlet<br/>/TestServlet/test</td> <td>http://localhost:8080/HttpSer/TestServlet<br/>http://localhost:8080/HttpSer/TestServlet/test</td> </tr><tr><td>模糊匹配</td> <td>/*<br/>/TestServlet/*<br/>/*.do</td> <td>http://localhost:8080/HttpSer/任意路径<br/>http://localhost:8080/HttpSer/TestServlet/任意路径<br/>http://localhost:8080/HttpSer/任意路径.do</td> </tr></tbody></table> **注意** 1)url-pattern要么以 / 开头,要么以*开头。 例如, TestServlet是非法路径。 2)不能同时使用两种模糊匹配,例如 /TestServlet/*.do是非法路径 3)当有输入的URL有多个servlet同时被匹配的情况下:   3.1 精确匹配优先。(长的最像优先被匹配)   3.2 以后缀名结尾的模糊url-pattern优先级最低!!! ### 3servlet生命周期: 1. 生命周期的引入: Servlet的生命周期: servlet类对象什么时候创建,什么时候调用什么方法,什么时候销毁。 以前的对象: new Student(); stu.study(); stu=null; Servlet程序的生命周期由tomcat服务器控制的!!!! 1. Servlet重要的四个生命周期方法: 构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时候创建servlet对象 只调用1次。证明servlet对象在tomcat是单实例的。 init方法: 创建完servlet对象的时候调用。只调用1次。 service方法: 每次发出请求时调用。调用n次。 destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。只调用1次。 1. 代码演示: ~~~ @WebServlet(name="TestServlet",urlPatterns={"/TestServlet"}) public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; int i=0; /** * 1.构造方法,只被调用一次 */ public TestServlet() { super(); System.out.println("构造方法>>>>"); } /** * 2.init初始化方法,在构造方法后只被调用一次 * 有参数的init方法会调用init方法;;一般覆盖无参数的init方法; */ @Override public void init() throws ServletException { // TODO Auto-generated method stub super.init(); System.out.println("inti>>>>"); } /** * 3.service方法,发生请求和响应时调用的方法,次数不限 * 一般是重写doget和dopost,此去只是方便演示 */ @Override protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { System.out.println("service>>>" +i++); } /** * 4.destory方法,只有在停止服务器和重新部署web应用时调用 */ @Override public void destroy() { System.out.println("destory"); super.destroy(); } } #输出结果:http://localhost:8080/HttpSer/TestServlet。连续访问四次,得到下面的结果: 构造方法>>>> inti>>>> service>>>0 service>>>1 service>>>2 service>>>3 Oct 11, 2015 8:53:52 PM org.apache.catalina.core.StandardContext reload INFO: Reloading Context with name [/HttpSer] has started destory ~~~ 1. 伪代码演示: ~~~ Tomtcat内部代码运行: 1)通过映射找到到servlet-class的内容,字符串: com.rlovep.serlvet.TestServlet 2)通过反射构造TestServlett对象 2.1 得到字节码对象 Class clazz = class.forName(" com.rlovep.serlvet.TestServlet"); 2.2 调用无参数的构造方法来构造对象 Object obj = clazz.newInstance(); ---1.servlet的构造方法被调用 3)创建ServletConfig对象,通过反射调用init方法 3.1 得到方法对象 Method m = clazz.getDeclareMethod("init",ServletConfig.class); 3.2 调用方法 m.invoke(obj,config); --2.servlet的init方法被调用 4)创建request,response对象,通过反射调用service方法 4.1 得到方法对象 Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class); 4.2 调用方法 m.invoke(obj,request,response); --3.servlet的service方法被调用 5)当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法 5.1 得到方法对象 Method m = clazz.getDeclareMethod("destroy",null); 5.2 调用方法 m.invoke(obj,null); --4.servlet的destroy方法被调用 ~~~ 1. 图像演示如下: ![1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001204b1a.png "") ### 4自动加载servlet: 默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。 改变servlet创建对象的时机: 提前到加载web应用的时候!!! 在servlet的配置信息中,加上一个或者加上注解(loadOnStartup=1)即可: ~~~ <servlet> <!-- servlet的内部名称,自定义。尽量有意义 --> <servlet-name>TestServlet</servlet-name> <!-- servlet的类全名: 包名+简单类名 --> <servlet-class>com.rlovep.serlvet.TestServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> 或者: @WebServlet(name="TestServlet",loadOnStartup=1,urlPatterns={"/TestServlet"}) ~~~ ### 5多用户问题: 注意: servlet对象在tomcat服务器是单实例多线程的。可以有多个用户; 因为servlet是多线程的,所以当多个线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。 解决办法: 1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步) 2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。 ### 6Servlet常用对象: servlet:有几个比较有用的对象: ~~~ 1.HttpServletRequest 请求对象 http协议中已讲 2.HttpServletResponse 响应对象 http协议中已讲 3.ServletConfig servlet配置对象 4.ServletContext Servlet的上下文对象。对整个web应用有效 5.HttpSession 会话对象,当一个用户向服务器发送第一个请求时,服务器为其建立一个session,并为此session创建一个标识号; ~~~ ### ServletConfig对象介绍: ServletConfig对象: 主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象) 可以直接从getServletConfig方法;或者自己在有参的init中获得 . 在web.xml中创建参数:一样有两种方法: ~~~ <servlet> <!-- servlet的内部名称,自定义。尽量有意义 --> <servlet-name>TestConfig</servlet-name> <!-- servlet的类全名: 包名+简单类名 --> <servlet-class>com.rlovep.serlvet.TestConfig</servlet-class> <init-param> <param-name>name</param-name> <param-value>peace</param-value> </init-param> </servlet> 或者: @WebServlet(urlPatterns={"/TestConfig"}, initParams={@WebInitParam(name="driver",value="com.mysql*") ,@WebInitParam(name="url",value="jdbc*"), @WebInitParam(name="user",value="root"), @WebInitParam(name="pass",value="123456")}) ~~~ 测试如下: ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletConfig servletConfig = getServletConfig(); //得到servlet的名字 System.out.println(servletConfig.getServletName()); //根据参数名获取参数值 String name=servletConfig.getInitParameter("user"); System.out.println(name+">>>>>"); //获取所有参数名称 Enumeration<String> names = servletConfig.getInitParameterNames(); while(names.hasMoreElements()){ String s=names.nextElement(); System.out.println(s+"="+servletConfig.getInitParameter(s)); } } ~~~ ### ServletContext对象介绍: **1. 引入** ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一 个ServletContext对象。 **2. 对象引用的得到** 创建时机:加载web应用时创建ServletContext对象。 得到对象: 从ServletConfig对象的getServletContext方法得到或者直接调用ServletContext servletContext = getServletContext(); **3. 核心api** ~~~ java.lang.String getContextPath() --得到当前web应用的路径 java.lang.String getInitParameter(java.lang.String name) --得到web应用的初始化参数 java.util.Enumeration getInitParameterNames() void setAttribute(java.lang.String name, java.lang.Object object) --域对象有关的方法 java.lang.Object getAttribute(java.lang.String name) void removeAttribute(java.lang.String name) RequestDispatcher getRequestDispatcher(java.lang.String path) --转发(类似于重定向) java.lang.String getRealPath(java.lang.String path) --得到web应用的资源文件 java.io.InputStream getResourceAsStream(java.lang.String path) ~~~ **4. 演示如下** ~~~ ServletContext servletContext = getServletContext(); //得到当前web应用路径 System.out.println("路径:"+servletContext.getContextPath()); //根据参数名获得参数值 System.out.println("AAA="+servletContext.getInitParameter("AAA")); //获取所有参数名称 Enumeration<String> names = servletContext.getInitParameterNames(); while(names.hasMoreElements()){ String s=names.nextElement(); System.out.println(s+":"+servletContext.getInitParameter(s)); } //设置域对象,整个web应用有效 servletContext.setAttribute("name","peace"); servletContext.setAttribute("age", "23"); //获得域对象 System.out.println("name"+servletContext.getAttribute("name")); System.out.println("age"+servletContext.getAttribute("age")); //删除域对象 servletContext.removeAttribute("age"); System.out.println("age"+servletContext.getAttribute("age")); ~~~ ### 7.转发和重定向; ### 域对象介绍: 域对象:作用是用于保存数据,获取数据。可以在不同的动态资源(servlet)之间共享数据。 案例: ~~~ #通过重定向,使用实体内容传递数据,一般只能存储字符 Servlet1 传数据:name=eric response.sendRedirect("/Servlet2?name=eric") Servlet2接收: String request.getParameter("name"); #通过域对象传递:可以传递任何数据; ServletContext就是一个域对象,上面有介绍怎么用 保存数据:void setAttribute(java.lang.String name, java.lang.Object object) 获取数据: java.lang.Object getAttribute(java.lang.String name) 删除数据: void removeAttribute(java.lang.String name) ServletContext域对象:作用范围在整个web应用中有效!!! 所有域对象: HttpServletRequet 域对象 测试; ServletContext域对象 HttpSession 域对象 PageContext域对象 ~~~ ### 重定向: **重定向是服务器告诉浏览器,重新请求另一页面,请求信息丢失更新** a)地址栏会改变,变成重定向到地址。 b)重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。 c)不能在重定向的过程,把数据保存到request中。 测试如下: ~~~ 1.建立一个TestRedect servlet: protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 保存数据到request域对象 */ request.setAttribute("name", "rose"); //重定向 /** * 注意:可以跳转到web应用内,或其他web应用,甚至其他外部域名。 */ //request域数据会丢失 response.sendRedirect("/HttpSer/GetData"); //重定向到外部域名: //response.sendRedirect("www.baidu.com"); } 2.建立一个GetData的servlet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("hello"); System.out.println("获得域对象"+request.getAttribute("name")); } ~~~ **现象如下:** 1.地址栏从[http://localhost:8080/HttpSer/TestRedect](http://localhost:8080/HttpSer/TestRedect)变为[http://localhost:8080/HttpSer/GetData](http://localhost:8080/HttpSer/GetData); 2.request域对象数据丢失:获得域对象null ### 转发: **转发是服务器将请求信号封装后转发到另一个servlet页面,请求信息会保存** a)地址栏不会改变 b)转发只能转发到当前web应用内的资源 c)可以在转发过程中,可以把数据保存到request域对象中 测试如下: ~~~ 1.建立一个TestRedect servlet: protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * 保存数据到request域对象 */ request.setAttribute("name", "rose"); //转发 /** * 注意:不能转发当前web应用以外的资源。 */ /*RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/GetDataServlet"); rd.forward(request, response);*/ this.getServletContext(). getRequestDispatcher("/GetData").forward(request, response); } 2.建立一个GetData的servlet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("hello"); System.out.println("获得域对象"+request.getAttribute("name")); } ~~~ **现象如下:** 1.地址栏没有变化 2.request域对象数据没有丢失:获得域对象rose 来自一条小鲨鱼(rlovep.com) [代码下载](https://github.com/wpeace1212/BlogSource/tree/master/HttpSer/src/com/rlovep/serlvet)
';

http协议介绍(servlet)

最后更新于:2022-04-01 14:17:15

> 本文是servlet的入门篇,主要简单介绍下http协议 ### 1.什么是http _ 1.http协议:_ 1. 复杂解释:   http(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。 2. 简单说:   对浏览器客户端 和 服务器端 之间数据传输的格式规范. 3. 协议版本:   http1.0:当前浏览器客户端与服务器端建立连接之后,只能发送一次请求,一次请求之后连接关闭。   http1.1:当前浏览器客户端与服务器端建立连接之后,可以在一次连接中发送多次请求。(基本都使用1.1)     请求一次资源就会出现一次请求,比如三张图片,就有三次请求,如果图片是一样 的就只有一次请求; **2.查看http协议的工具:** 1. chrome(谷歌)浏览器查看:   右键点击查看元素(inspect element),点击network即可; ![1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00111c5e6.png "") 2. 火狐:   使用火狐的firebug插件(右键->firebug->网络) 3. 使用系统自带的telnet工具(远程访问工具) a)telnet localhost 8080 访问tomcat服务器 b)ctrl+] 回车.可以看到回显 c)输入请求内容,回车,即可查看到服务器响应信息。 ~~~ GET / HTTP/1.1 Host: www.baidu.com ~~~ ### 2.http协议内容: 1. 请求: ~~~ GET /HttpSer HTTP/1.1 Host: localhost:8080 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.85 Chrome/45.0.2454.85 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8 ~~~ 1. 响应: ~~~ HTTP/1.1 302 Found Server: Apache-Coyote/1.1 Location: http://localhost:8080/HttpSer/ Transfer-Encoding: chunked Date: Fri, 09 Oct 2015 08:55:42 GMT ~~~ 下面将对这两个协议进行介绍: ### 3.http请求介绍: ~~~ GET /HttpSer HTTP/1.1-请求行 Host: localhost:8080--请求头;有多个key-value组成 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.85 Chrome/45.0.2454.85 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8 --可选,实体内容; ~~~ ### 请求行介绍 GET /HttpSer HTTP/1.1 -请求行 **1.请求资源的URL和URI比较:**     URL: 统一资源定位符。[http://localhost:8080/HttpSer/index.html](http://localhost:8080/HttpSer/index.html)。只能定位互联网资源。是URI 的子集.     URI: 统一资源标记符。/HttpSer/index.html。用于标记任何资源。可以是本地文件系统,局域网的资源(//192.168.14.10/HttpSer/index.html),可以是互联网。 **2.请求方式:**     常见的请求方式: GET 、 POST、 HEAD、 TRACE、 PUT、 CONNECT 、DELETE     常用的请求方式: GET(有将实体信息放在浏览器地址栏) 和 POST(隐藏实体内容) **3. servlet获得请求行信息:_** ~~~ /*** 1.1请求行的获得*/ System.out.println("请求方式:"+request.getMethod());//获得提交方式 System.out.println("请求URI:"+request.getRequestURI());//获得uri System.out.println("请求url:"+request.getRequestURL());//获得url System.out.println("获得协议:"+request.getProtocol());//获得所用协议 ##输出: 请求方式:GET 请求URI:/HttpSer/TestRequst 请求url:http://localhost:8080/HttpSer/TestRequst 获得协议:HTTP/1.1 ~~~ **4. 测试提交方式:** 新建立web工程,建立TestMethod.html文件: ![4](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00114d4e7.png "") 建立Servlet类TestMethod.java修改get和post方法: ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("get 方式提交"); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("post 方式提交"); } ~~~ 运行tomcat可以看淡提交方式的不同:浏览器地址栏显示的不同,servlet调用的方法也不同; get提交 ![2](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e00116ac98.png "") post提交 ![3](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001180467.png "") **经过对比请求可以发现** get方式在请求行多了?name=wang&pass=123 post多了实体内容:Content-Type: application/x-www-form-urlencoded 请求内容同如下: ~~~ #get方式: GET /HttpSer/TestMethod?name=wang&pass=123 HTTP/1.1 Host: localhost:8080 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.85 Chrome/45.0.2454.85 Safari/537.36 Referer: http://localhost:8080/HttpSer/testMethod.html Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8 #post方式: POST /HttpSer/TestMethod HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 18 Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Origin: http://localhost:8080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.85 Chrome/45.0.2454.85 Safari/537.36 Content-Type: application/x-www-form-urlencoded Referer: http://localhost:8080/HttpSer/testMethod.html Accept-Encoding: gzip, deflate Accept-Language: en-US,en;q=0.8 ~~~ ### 请求头介绍: **1. 请求头介绍:** 请求头主要包含一些有用信息: 1.Host: localhost:8080主机地址和端口 2.Connection: keep-alive 连接方式 3.User-Agent:浏览器的一些信息 4.Referer:来访页面 5.Content:实体内容;post才有 **2. servlet获得请求头主要的方法:** request.getHeader(“Host”));通过建获得相应请求的内容; Enumeration headerNames = request.getHeaderNames();获得请求头所有的键值 **3. 演示如下:** 修改doget方法 ~~~ /*** 设置参数查询的编码 *该方法只能对请求实体内容的数据编码起作用。POST提交的数据在实体内容中,所以该方法对POST方法有效! *GET方法的参数放在URI后面,所以对GET方式无效!!! */ request.setCharacterEncoding("utf-8"); /** * 1.1请求行的获得 */ System.out.println("请求方式:"+request.getMethod()); System.out.println("请求URI:"+request.getRequestURI()); System.out.println("请求url:"+request.getRequestURL()); System.out.println("获得协议:"+request.getProtocol()); /** * 1.2请求头的获得 */ //通过键获得请求头的内容 System.out.println("获得host:"+request.getHeader("Host")); System.out.println("获得浏览器的User-Agent:"+request.getHeader("User-Agent")); //通过迭代器迭代,获得键 在取键值 Enumeration<String> headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()){ String key=headerNames.nextElement(); System.out.println(key+":"+request.getHeader(key)); } /** * 得到请求实体内容 * 比如:实体为name=peace&pass=1234 */ ServletInputStream in = request.getInputStream(); byte[] buf=new byte[1024]; int len=0; while((len=in.read(buf))!=-1){ String str=new String(buf,0,len); System.out.println(str); } #输出如下: 请求方式:GET 请求URI:/HttpSer/TestRequst 请求url:http://localhost:8080/HttpSer/TestRequst 获得协议:HTTP/1.1 获得host:localhost:8080 获得浏览器的User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.101 Chrome/45.0.2454.101 Safari/537.36 host:localhost:8080 connection:keep-alive accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 upgrade-insecure-requests:1 user-agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/45.0.2454.101 Chrome/45.0.2454.101 Safari/537.36 referer:http://localhost:8080/HttpSer/testMethod.html accept-encoding:gzip, deflate, sdch accept-language:en-US,en;q=0.8 cookie:CNZZDATA1255712369=1133597550-1443969628-%7C1443969628//此去后面文章会介绍; ~~~ ### 输入参数的介绍: **1. 输入参数:** 输入参数: 对于get来说就是跟在url后面的内容 /TestParam?name=”peace”&password=”sisi” ;name=”peace”&password=”sisi”这就是输入参数 对于post来说就是实体内容,不可见 **2. Servlet中获得输入参数的方法:** String name=request.getParameter(“name”);获得对应输入参数名字的内容 Enumeration params = request.getParameterNames();获得所有输入参数的名字,返回一个迭代器 String[] hobits = request.getParameterValues(names);如果对应名字的内容是一个数组,使用这个方法获得,比如复选框 **3. 演示如下:** 1.建立testParam.html ![5](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0011971bd.png "") 2.修改doget方法: ~~~ /** * 设置参数查询的编码 * 该方法只能对请求实体内容的数据编码起作用。POST提交的数据在实体内容中,所以该方法对POST方法有效! * GET方法的参数放在URI后面,所以对GET方式无效!!! */ request.setCharacterEncoding("utf-8"); //获得所有的方式 System.out.println("提交方式:"+request.getMethod()); //获得输入参数 String name=request.getParameter("name"); String pass=request.getParameter("password"); System.out.println("name:"+name+",pass:"+pass); /*此去为如果get方式提交出现乱码,使用; * if("GET".equals(request.getMethod())){ password = new String(password.getBytes("iso-8859-1"),"utf-8"); }*/ System.out.println(">>>>>>>>>>>>>>>>>"); //获得所有输入参数的名字 Enumeration<String> params = request.getParameterNames(); while(params.hasMoreElements()) { String names=params.nextElement(); //如果是复选框,使用getParameterValues(names);方法 if("hobit".equals(names)){ System.out.println(names+":"); String[] hobits = request.getParameterValues(names); for(String s:hobits) System.out.print(s+","); System.out.println(); } else{ System.out.println(names+":"+request.getParameter(names)); } } ##输出结果如下: 提交方式:POST name:peace,pass:124 >>>>>>>>>>>>>>>>> name:peace password:124 gender:男 籍贯:湖南 hobit: 篮球,足球, info:一条小鲨鱼peace id:001 ~~~ ### 4.http响应介绍: ~~~ HTTP/1.1 302 Found ---响应行 Server: Apache-Coyote/1.1 ---响应头, 有多个key-value组成 Location: http://localhost:8080/HttpSer/ Transfer-Encoding: chunked Date: Fri, 09 Oct 2015 08:55:42 GMT ~~~ ### 响应行介绍: HTTP/1.1 302 Found **1基本介绍** 1.HTTP/1.1:采用的协议 2.302:状态码 常见的状态: 200 : 表示请求处理完成并完美返回 302: 表示请求需要进一步细化。 404: 表示客户访问的资源找不到。 500: 表示服务器的资源发送错误。(服务器内部错误) 3.Found:状态描述,常见ok和found **2. servlet中的方法** tomcat服务器把请求信息封装到HttpServletRequest对象,且把响应信息封装到HttpServletResponse response.setStatus(404);//设置状态码 response.sendError(404);// 设置错误页面 **3. 演示如下** ~~~ response.setStatus(404);//错误代码,没有反应 response.sendError(404);// 发送404的状态码+404的错误页面 #输出结果: HTTP/1.1 404 Not Found Server: Apache-Coyote/1.1 Content-Type: text/html;charset=ISO-8859-1 Content-Language: en Content-Length: 949 Date: Sat, 10 Oct 2015 13:09:53 GMT ~~~ ![6](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0011baa56.png "") ### 响应头介绍: **1. 基本介绍** 格式:Server: Apache-Coyote/1.1;Server响应头名,后面的是响应值; 头里面主要包括:Server,服务器类型;Location:跳转网页地址 Conten*:实体内容 **2. servlet中的方法** response.setHeader(“server”, “JBoss”);修改对应头名的内容; **3. 演示如下** ~~~ //修改服务器类型 response.setHeader("server", "JBoss"); /** * 修改实体内容 */ //浏览器能直接看到的内容就是实体内容 response.getWriter().println("hello peace");//字符内容,常用 //response.getOutputStream().write("hello world".getBytes());//字节内容。不能两个同时使用 #输出如下: HTTP/1.1 200 OK server: JBoss Content-Length: 12 Date: Sat, 10 Oct 2015 13:11:04 GMTHTTP/1.1 200 OK server: JBoss Content-Length: 12 Date: Sat, 10 Oct 2015 13:11:04 GMT ~~~ ![7](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0011d36e0.png "") ### 几个常要的方面介绍 1. 测试重定向:与转发不同 ~~~ /** * 测试重定向:与转发不同 * 使用请求重定向:发送一个302状态吗+location的响应 * */ response.setStatus(302);//设置状态码 response.setHeader("location", "/HttpSer/adv.html");//设置重定向页面 //简单写法 // response.sendRedirect("/HttpSer/adv.html"); #输出: HTTP/1.1 302 Found Server: Apache-Coyote/1.1 location: /HttpSer/adv.html Content-Length: 12 Date: Sat, 10 Oct 2015 13:15:26 GMT ~~~ 1. 定时刷新: ~~~ /** * 定时刷新 * 原理:浏览器解析refresh头,得到头之后重新请求当前资源 * */ //response.setHeader("refresh", "1");//每隔1秒刷新一次 //隔5秒后转到另外的资源 //response.setHeader("refresh", "5;url=/HttpSer/adv.html"); #输出: HTTP/1.1 200 OK Server: Apache-Coyote/1.1 refresh: 1 Content-Length: 12 Date: Sat, 10 Oct 2015 13:18:39 GMT HTTP/1.1 200 OK Server: Apache-Coyote/1.1 refresh: 5;url=/HttpSer/adv.html Content-Length: 12 Date: Sat, 10 Oct 2015 13:21:29 GMT ~~~ 1. 设置编码: ~~~ response.setCharacterEncoding("utf-8"); /** * 1. 服务器发送给浏览器的数据类型和内容编码 */ //response.setHeader("content-type", "text/html");//设置内容为html //response.setContentType("text/html;charset=utf-8");//和上面代码等价。推荐使用此方法 //response.setContentType("text/xml");//设置内容为xml //response.setContentType("image/png");//设置内容为图片 ~~~ 1. 设置为下载方式打开文件: ~~~ /** * 设置以下载方式打开文件 */ //response.setHeader("Content-Disposition", "attachment; filename="+file.getName()); ~~~ 1. 发送硬盘图片给浏览器: ~~~ File file = new File("/media/peace/本地磁盘/andriod/1.png");//WebContent /** * 发送图片 */ FileInputStream in = new FileInputStream(file); byte[] buf = new byte[1024]; int len = 0; //把图片内容写出到浏览器 while( (len=in.read(buf))!=-1 ){ response.getOutputStream().write(buf, 0, len); } ~~~ 来自一条小鲨鱼(rlovep.com) [代码下载](https://github.com/wpeace1212/BlogSource/tree/master/HttpSer/src/com/rlovep/Http)
';

Eclipse部署动态web项目方法

最后更新于:2022-04-01 14:17:13

> 和MyEclipse不一样,在Eclipse中做的Web项目默认是不支持将项目发布到Web服务器上的,会发布到工作空间的某个目录,因此无法在外部启动Tomcat来运行Web项目,只有打开Eclipse中的服务器,才能运行Web项目。所以要对Eclipse进行修改,才能将做好的项目,发布到Tomcat服务器上,发布到服务器上的Webapps文件夹下。本文介绍两种方法; ### 1.通过修改Servers下Tomcat的配置: show view—>servers下找到需要修改的tomcat—>右击完成一下几个步骤: ①停止eclipse内的Tomcat服务器(stop) ②删除该容器中部署的项目(add and remove) ③清除该容器相关数据(clean) ④打开tomcat的修改界面(open) ⑤找到servers location,选择第二个(User tomcat Installation) ⑥修改deploy path为webapps ⑦保存关闭 需要说明的是①②③必须操作,否则下面的步骤会被置灰无法操作。 修改后的图像如下: ![1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded26c3001.png "") ### 2.验证是否修改成功: 1. 通过Eclipse建立一个Dynamic Web Project; 1. 添加一个index.html的页面; ~~~ <body> hello peace </body> ~~~ 1. 在WebContent右击选择New–>Other–>Web–>Servlet: 配置如下:com.rlovep.Hello.Hello.java ![2](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded26dc3e6.jpg "") ![3](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded26f3f58.png "") 此去注意我的servlet是3.0以上的了,可以使用注解:不用再修改web.xml; ~~~ @WebServlet("/Hello")//注解url:/Hello public class Hello extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("hello peace"); } } ~~~ 1. 右键点击(add and remove)将工程加入Tomcat: ![4](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0010692a4.png "") 1. 即可在服务器上的Webapps文件夹下看到你的工程文件夹;(比如我的HttpSer) ![5](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0010864cb.png "") 1. 运行Tomcat可以看到如下图: 主页:[http://localhost:8080/HttpSer/](http://localhost:8080/HttpSer/) ![6](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e001099501.png "") Hello页(servlet):[http://localhost:8080/HttpSer/Hello](http://localhost:8080/HttpSer/Hello) ![7](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0010ad472.png "") ### 3.第二种方法:通过tomcatPlugin插件 下载地址:[http://www.eclipsetotale.com/tomcatPlugin/](http://www.eclipsetotale.com/tomcatPlugin/) 1. 解压到Eclipse下的plugins目录下重启后会看到3只小猫,并配置Window->perferences->tomcat中的tomcat home为tomcat目录应用。 ![8](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0010cb1ea.png "") 2. 项目的tomcat属性配置如下:主要修改:勾上Is a Tomcat Project;修改Context name为你想要的名字 ![9](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570e0010e7aed.png "") 3. 右键工程run,run server;运行程序; 可以获得上面一样的结果; 来自一条小鲨鱼(rlovep.com)
';

xml约束技术之dtd

最后更新于:2022-04-01 14:17:10

> DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。这篇文章作简单介绍下DTD的用法。想学习完整的请点击下面w3c的教程。 ### 1.[DTD官方教程](http://www.runoob.com/dtd/dtd-tutorial.html) ##2.xml约束技术: DTD约束:语法相对简单,功能也相对简单。先出现 Schema约束:语法相对复杂,功能也相对强大。采用和xml语法类似的编写方式,Schema约束出现就是为了替换DTD约束。 ### 3.DTD简介:   文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。 ### 3.1导入DTD的方式: 1.内部导入: ~~~ #导入方式: <!DOCTYPE root-element [element-declarations]> #实例: <?xml version="1.0"?> <!DOCTYPE note [ <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ]> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend</body> </note> ~~~ 1. (第二行)定义此文档是 note(根标签) 类型的文档。 1. (第三行)定义 note 元素有四个元素(标签):”to、from、heading,、body” 1. (第四行)定义 to 元素为 “#PCDATA” 类型 1. (第五行)定义 frome 元素为 “#PCDATA” 类型 1. (第六行)定义 heading 元素为 “#PCDATA” 类型 1. (第七行)定义 body 元素为 “#PCDATA” 类型 2.外部导入方式:   本地文件: ~~~ #导入方式: <!DOCTYPE note SYSTEM "note.dtd"> #note.dtd文件内容: <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ~~~   公共的外部导入:一般项目采用公共外部导入,比如ssh的xml文件基本上就是采用了这种方式 ~~~ #导入方式: <!DOCTYPE 根元素 PUBLIC "http://rlovep.com/peace.dtd"> #如hibernate.cfg.xml: <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> ~~~ ### 3.2DTD语法:   1.约束标签  语法: ~~~ <!ELEMENT 元素名称 类别> 或 <!ELEMENT 元素名称 (元素内容)> ~~~  类别: 1. 空标签: EMPTY。 表示元素一定是空元素.例如:<bb/>: ~~~ 顺序问题: <!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)>: 按顺序出现子标签 次数问题: 标签 : 必须且只出现1次。 标签+ : 至少出现1次 标签* : 0或n次。 标签? : 0 或1次。 声明"非.../既..."类型的内容 ~~~   2.约束属性:  语法: ~~~ <!ATTLIST 元素名称 属性名称 属性类型 默认值> ~~~  属性类型: ~~~ CDATA :表示普通字符串 (en1|en2|..): 表示一定是任选其中的一个值 ID:表示在一个xml文档中该属性值必须唯一。值不能以数字开头 ~~~  默认值: ~~~ #REQUIRED 属性值是必需的 #IMPLIED 属性不是必需的 #FIXED value 属性不是必须的,但属性值是固定的 ~~~ ### 3.3测试如下,请细看注释: ~~~ <?xml version="1.0"?> <!DOCTYPE note [ <!ELEMENT note (to,from+,heading*,body?,(br|b))> <!--带有子序列的元素,需要按照先后顺序出现; to只能出现一次 from最少出现一次 heading次数随意 body出现零次或者一次 非出现br就出现b --> <!--元素约束--> <!ELEMENT to (#PCDATA)><!--pcdata元素--> <!ELEMENT from ANY><!--任何内容的元素--> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> <!ELEMENT br EMPTY><!--空元素--> <!ELEMENT b EMPTY><!--空元素--> <!--属性约束--> <!ATTLIST to number CDATA #REQUIRED><!--必须有属性值出现,且属性值类型为字符串--> <!ATTLIST from length CDATA "10"><!--默认属性值,不写出属性时属性值为10--> <!--假如您不希望强制作者包含属性,并且您没有默认值选项的话,请使用关键词 #IMPLIED。--> <!ATTLIST heading length CDATA #IMPLIED> <!ATTLIST body length CDATA #FIXED "123"><!--属性拥有固定的值,并不允许作者改变这个值--> <!ATTLIST br type (check|cash) "cash"><!--属性值可以为check和cash中的一个--> ]> <note> <to number="1234">Tove</to> <from>Jani</from> <heading length="10">Reminder</heading> <body length="123">Don't forget me this weekend</body> <br type="check"/> </note> ~~~
';

Tomcat安装与使用

最后更新于:2022-04-01 14:17:08

> 主要讲解Tomcat的 安装与使用,讲解ubuntu版本和windows。 ### 下载与安装: 1)到apache官网。www.apache.org [http://jakarta.apache.org](http://jakarta.apache.org)(产品的主页) 2) 安装版:window (exe、msi) linux(rmp) 压缩版:window(rar,zip) linux(tar,tar.gz)建议下载压缩版 3)下载压缩版,解压到本地 解压后的文件夹如下:windows和linux下都是一样的。 ![1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded254312f.png "") ### 运行和关闭tomcat #### windows启动软件: 到/bin目录下找到startup.bat ,双击这个文件 弹出命令窗口,显示如下:表示运行正常 ![2](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded25594e9.png "") #### ubuntu下启动软件: 到/bin目录下打开终端,输入命令:./startup.sh 显示信息如下: ![3](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded257eaaa.png "") #### 打开浏览器,输出以下地址 [http://localhost:8080](http://localhost:8080) 显示如下 ![4](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded2598a3f.png "") #### 关闭软件 windows下到/bin目录下找到/shutdown.bat,双击这个文件即可! ubuntu下在终端输入(在bin目录下):./shutdown.sh ### Tomcat常见问题: #### 闪退问题    原因:tomcat软件是java语言开发的。 tomcat软件启动时,会默认到系统的环境变量中查找一个名称叫JAVA_HOME的变量。这个变量的作用找到tomcat启动所需的jvm。 windows下:    解决办法: 到环境变量中设置JAVA_HOME的变量    JAVA_HOME= C:\Program Files\Java\jdk1.6.0_30 (注意别配置到bin目录下) ubuntu下:    解决办法: ~~~ $ sudo gedit /etc/environment #在environment中修改PATH,追加JDK路径,添加CLASSPATH与JAVA_HOME后如下: export JAVA_HOME=/usr/lib/jvm/jdk8 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib PATH="/usr/lib/jvm/jdk8/bin:/usr/local/sbin:/usr/local/bin: /usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" ~~~ #### 端口占用的错误    原因: tomcat启动所需的端口被其他软件占用了!    解决办法:    a)关闭其他软件程序,释放所需端口    b)修改tomcat软件所需端口    c)找到并修改/conf/server.xml文件 ~~~ <Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> ~~~ ### Tomcat的目录结构: ~~~ |-bin: 存放tomcat的命令。 catalina.bat(sh) 命令: startup.bat(sh) -> catalina.bat(sh) start shutdown.bat - > catalina.bat(sh) stop |- conf: 存放tomcat的配置信息。其中server.xml文件是核心的配置文件。 |-lib:支持tomcat软件运行的jar包。其中还有技术支持包,如servlet,jsp |-logs:运行过程的日志信息 |-temp: 临时目录 |-webapps: 共享资源目录。web应用目录。(注意不能以单独的文件进行共享) |-work: tomcat的运行目录。jsp运行时产生的临时文件就存放在这里 ~~~ ### 配置文件的修改: #### server.xml的修改 **端口,和编码的修改:** ~~~ <Connector port="8080" #这里修改端口 protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" useBodyEncodingForURI="true" #解决大多数中文编码问题/> ~~~ **修改host主机** ~~~ <Host name="localhost"#默认的主机名,这里修改后,还需修改系统的host文件 appBase="webapps"#默认存放工程的文件夹 unpackWARs="true" autoDeploy="true"> ~~~ **修改访问工程的路径**不建议修改: 打开server.xml,在这个主机中增加一个Context即可 即可以完成项目发布,之后通过?localhost:8080/hello就可以访问该目录 ![5](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded25bed03.png "") Context表示访问的虚拟路径,path表示要访问的网页下文路径,docBase表示要访问的文件夹所在路径,reloadable表示是否在修改之后进行重新启动,如果使用eclipse开发建议设置为false,因为在eclipse中会通过debug进行启动。 #### web.xml的修改 **主页的修改** ~~~ <welcome-file-list> <welcome-file>index.html</welcome-file>#一般创建web项目时默认的主页是index.html index.jsp <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file>#;你可以修改成你的将你的主页放置在工程根目录就行; <welcome-file>hello.jsp</welcome-file>#比如加一个你自己的主页; </welcome-file-list> ~~~ **是否列出列表** listings表示是否在显示页面时打开文件列表,建议在调试时打开,方便查询一些特殊的网页文件,比如文件名太长的等; ~~~ <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>true</param-value>#将此去改为true </init-param> <load-on-startup>1</load-on-startup> </servlet> ~~~ 修改后例子: ![61](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded25d23e3.png "") ### web应用和目录结构: ~~~ |- WebRoot : web应用的根目录 |- 静态资源(html+css+js+image+vedio) |- WEB-INF : 固定写法。 |-classes: (可选)固定写法。存放class字节码文件 |-lib: (可选)固定写法。存放jar包文件。 |-web.xml 注意: 1)WEB-INF目录里面的资源不能通过浏览器直接访问 2)如果希望访问到WEB-INF里面的资源,就必须把资源配置到一个叫web.xml的文件中。 ~~~ ### URL简介: ~~~ URL全名叫统一资源定位符,用于定位互联网的资源。 问题: http://localhost:8080/examples/hello.html http:// 协议。http协议。 localhost 域名。为了找到IP地址。 本地域名: localhost 外部域名:www.baidu.com 8080: tomcat默认的端口 3306:mysql数据库的端口 1521: orace数据库的端口。 /examples: web应用的名称。默认情况下,在webapps目录下找 /hello.html : 资源名称。 ~~~ ### 手动开发动态资源(web) #### 最简单的例子: 在Tomcat文件下的webapps/examples 文件下建立一个html的文件,比如我建立了hello.html: ~~~ I am peace this is test ~~~ 运行Tomcat,在浏览器里面输入[http://localhost:8080/examples/hello.html](http://localhost:8080/examples/hello.html).显示如下: ![6](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded25ec9b3.png "") #### 手动servlet的例子: Servlet : 用java语言来编写动态资源的开发技术。 Servlet类只能交给tomcat服务器运行!(开发者自己不能运行) Servlet手动编写步骤: 1. 导入servlet的jar包:在Tomcat目录的lib文件下: ![7](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded260dc78.png "") 2. 编写一个类,继承HttpServlet并覆盖doGet的方法:如下: ~~~ package com.rlovep.servlet; import java.io.IOException; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Hander extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //解决中文乱码问题 resp.setContentType("text/html;charset=utf-8"); //向浏览器输出时间 resp.getWriter().write("这是第一个servlet程序。当前时间为:"+new Date()); } } ~~~ 1. 在工程目录下找到build文件,将对应类class的字节码(包括包文件)拷贝到:apache-tomcat-8.0.26/webapps/examples/WEB-INF/classes下 ![8](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded2626e51.png "") 1. 修改/examples/WEB-INF/web.xml的文件: 增加如下内容: ~~~ <!-- 配置一个servlet程序 --> <servlet> <!-- servlet的内部名称 ,可以自定义--> <servlet-name>HelloServlet</servlet-name> <!-- servlet类名: 包名+简单类名--> <servlet-class>com.rlovep.servlet.Hander</servlet-class> </servlet> <servlet-mapping> <!-- servlet的内部名称,和上面的名称保持一致!!!--> <servlet-name>HelloServlet</servlet-name> <!-- servlet的访问名称: /名称 --> <url-pattern>/hello</url-pattern> </servlet-mapping> ~~~ 1. 在浏览器中输入:[http://localhost:8080/examples/hello](http://localhost:8080/examples/hello).显示如下: ![9](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded26420be.png "") 建立成功 ### 工具开发动态资源 1. 创建web project (javaweb工程)ubuntu下是建立Dynamic web project 2.在WebRoot下建立静态资源文件:index.html 3.在src下建立动态资源文件 3.1 new -> Servlet( servlet的代码生成器) 3.2 写pacakge -> class名 -> 修改mapping url ![10](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded265ab12.png "") 1. 启动tomcat服务器 1. 访问servlet 主页:[http://localhost:8080/HttpProtocl](http://localhost:8080/HttpProtocl) ![11](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded267a7f1.png "") servlet:[http://localhost:8080/HttpProtocl/Auto](http://localhost:8080/HttpProtocl/Auto) ![12](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-13_570ded268dd6e.png "") 程序下载地址 [点击这里](https://github.com/wpeace1212/javaBlog/tree/master/HttpProtocl/src) 来自一条小鲨鱼(rlovep.com)
';

前言

最后更新于:2022-04-01 14:17:06

> 原文出处:[JavaWeb我画你阅](http://blog.csdn.net/column/details/java-wpeace.html) 作者:[peace1213](http://blog.csdn.net/peace1213) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # JavaWeb我画你阅 > 从最简单的开发环境搭建讲起,接着从servlet讲到jsp,再到框架ssh,以及数据库,Ajax讲解等
';