导图社区 Struts2
Struts2是一个基于MVC设计模式的Web轻量级应用框架,本质上相当于一个servlet,在MVC设计模式中Struts2作为控制器(Controller)来建立模型与视图的数据交互,Struts2是在 Struts 1和WebWork的技术基础上进行了合并。
编辑于2020-11-20 09:51:08SSH
Struts2是一个基于MVC设计模式的Web轻量级应用框架 本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互 Struts2是在 Struts 1和WebWork的技术基础上进行了合并 Struts2的体系结构与Struts 1的体系结构差别巨大 Struts2以WebWork为核心(拦截器机制处理请求)
Struts2框架搭建步骤:
/demo/hello.action-->StrutsPrepareAndExecuteFilter-->struts.xml-->HelloAction.java-->execute--->result--struts.xml---hello.jsp
导包:struts2-core
<!--增加struts2核心包--> <dependencies> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.5.17</version> </dependency> <dependencies>
配置启动容器web.xml
<!--增加struts2的配置文件信息--> <filter> <filter-name>struts2</filter-name> <!--通过核心控制器判断url地址是否已对应的后缀结尾--> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <!--默认的请求格式 .action和空 如果改成.do需要在struts.xml里修改请求后缀格式--> <url-pattern>*</url-pattern> </filter-mapping>
增加struts2的配置文件
resources 命名: struts.xml struts-plugin.xml struts-default.xml
配置模板
在web-inf里创建jsp文件 hello
在配置文件中配置请求sturts.xml
<!--修改struts2的请求后缀格式 多个用逗号隔开--> <constant name="struts.action.extension" value="do,htm"></constant> <!--struts2中所有的请求,都需要配置到此配置文件中--> <!--此配置文件中,key存在多个package--> <!--name:必须保证唯一,必输项 extends:使用的是struts-default 使用的是struts-default.xml中的pageckage的name值 必输项 namespace:命名空间默认是:/ --> <package name="demo" extends="struts-default" namespace="/demo"> <!--接口请求地址: name:请求名称 class:请求处理接收类 method:类中处理请求的方法名称 --> <action name="hello" class="com.xdl.action.HelloAction" method="execute"> <!--接收的是方法处理的结果集 name:方法返回的字符串值 action中可以存在多个result,但是name值不能相同 type:返回值类型 dispatcher:转发 value:返回值处理集合--> <result name="success" type="dispatcher">/WEB-INF/jsp/hello.jsp</result> </action> </package>
增加一个action处理类
struts2参数的传递
从前端获取数据到后端
public String name;
必须保持变量名称和请求接口地址中参数名称----名称一致
必须设置为全局变量
增加get和set方法
从后端获取数据到前端
同上 前端用${msg}接收
导入这个包 可以用标注的get set方法
Struts2+spring
- struts2整合之前 - 请求--->filter--->struts.xml-->action.java-->execute-->result-->jsp - struts2和spring整合之后 - 请求(struts2)-->filter--->struts.xml-->action(spring-IOC-controller)-->result(struts2)--->jsp
搭建struts2框架
导包 webmvc 中间包
<!--导入spring框架包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.9.RELEASE</version> </dependency> <!--导入struts2和spring的整合包--> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>2.3.16.3</version> </dependency>
配置启动容器web.xml
<!--加载spring配置信息--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--加载spring配置信息--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
增加spring的配置文件applicationContext.xml
<!--开启组件扫描--> <context:component-scan base-package="com.xdl.action"></context:component-scan>
在action中,增加@controller注解,将对象注入到spring的IOC容器中
修改struts.xml中的action对应的class属性(修改为spring容器中的bean的id,其实默认就是类名第一个字符小写即可)
结合JDBC使用查询功能
<!--导入数据库驱动包 mysql,连接池-->| <!--导入spring连接数据库的jdbc包-->
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.9.RELEASE</version> </dependency>
在spring的配置文件中,配置数据源和连接池信息
<!--配置数据源--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="c3p0"></property> </bean> <!--配置连接池--> <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="root"></property> <property name="password" value="123456"></property> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ydma"></property> </bean>
增加查询数据库的接口和实现类(接口类名要求首字母加I然后大写,实现类新建包impl)
@Service @Transactional(rollbackFor = Exception.class)//事务,遇到异常回退 如果标记类上,下面所有的方法都回退 同一个事物下,保证数据一致性的注解 public class CourseServiceImpl implements ICourseService { //@Resource//先按照名称匹配,其次按照类型进行匹配 @Autowired//只会按照类型匹配 推荐使用 private JdbcTemplate jdbcTemplate;//dao public List<Course> quertyCourseByUserId(Integer directionId) { String sql="select id,name,intro from course where direction_id=?"; Object[] params = {directionId}; //数据库查询 List<Course> list= jdbcTemplate.query(sql,params,new CourseMapper()); return list; }
增加关系对象映射文件mapper类
public class CourseMapper implements RowMapper { public Object mapRow(ResultSet rs, int i) throws SQLException { Course note = new Course(); note.setId(Integer.valueOf(rs.getString("id")));//"id":数据库中的字段名称 note.setIntro(rs.getString("intro")); note.setName(rs.getString("name")); return note; }
修改ListAction.java,调用接口进行查询
@Controller public class HelloList { public List<Course> courses; @Autowired public ICourseService courseService; public String execute(){ courses= courseService.quertyCourseByUserId(1); return "123"; } public List<Students> getStu() { return stu; } public void setStu(List<Students> stu) { this.stu = stu; } }
抽取jdbc数据源信息为属性文件
<!--应用属性文件--> <context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="NEVER"/> <!--配置连接池--> <bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${username}"></property> <property name="password" value="${password}"></property> <property name="driverClass" value="${driver}"></property> <property name="jdbcUrl" value="${url}"></property> </bean>
jdbc.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/ydma?useUnicode=true&characterEncoding=utf-8 username=root password=123456
结合jdbc实现删除功能(使用redirectAction重定向)
修改list.jsp文件,增加一个删除操作
修改struts.xml配置文件,增加一个删除的action
<!--删除操作--> <action name="delect" class="delectAction" method="execute"> <result name="success" type="redirectAction"> <!--重定向:重定向到/demo/List.do--> <param name="namespace">/demo</param> <param name="actionName">List</param> </result> <!--如果当前需要跳转的action和此action是在同一个namespace中,则可以如下写,不建议使用--> <!-- <result name="success" type="redirectAction">list</result>--> <result name="error" type="dispatcher">/WEB-INF/jsp/error.jsp</result>
增加一个DeleteAction.java文件
@Controller public class DelectAction { //只需要名称一致即可,不需要关心参数类型 //优势:支持类型转换(存在大量的类型转换器,其中时间字段,不支持转换) @Getter @Setter public String id; @Resource private ICourseService noteService; public String execute(){ int a= noteService.deleteNoteById(id); if (a > 0){ return "success"; } return "error"; } }
增加一个删除接口,并实现
public int deleteNoteById(String id) { String sql = "delete from course where id = ?"; Object[] params = {id}; int count = jdbcTemplate.update(sql,params); return count; }
模拟登陆
struts.xml
login.jsp
ToLogin.java
LoginAction.java
@Scope("prototype")//并发单例问题处理 //在有参数接受 发送的action中 //增加标注将单例取消
session的存储
使用ActionContext
第一种:sessionMap -- 不推荐使用 Map<String, Object> session = ActionContext.getContext().getSession(); session.put("username", "admin");
${username}
使用httpsession(需要servlet-api)
第二种:httpsession -- servlet-api 导入包-- 不推荐使用 HttpSession session = ServletActionContext.getRequest().getSession(); session.setAttribute("username1", "admin1");
${username1}
实现sessionaware接口
封装
public class BaseAction implements SessionAware { public Map<String,Object> session; public void setSession(Map<String, Object> session) { this.session = session; }
继承使用
session.put("username", "admin");
${username1}
struts2组件列表
Struts Prepare And Execute Filter
接收请求 拦截请求后缀(判断后缀是否符合要求) 封装数据到valueStack(值栈) 走大量拦截器 将请求转发到struts.xml,寻找对应的action
Action
package struts.xml文件中,可以存在多个,保证name值不同即可 一般就是项目中的模块名称
action 在同一个package中,可以存在多个,但是保证name值(请求名称)不同即可 class:接口的处理类,默认值 method:类中处理请求的方法名称,默认值
result 在同一个action中,可以存在多个,保证name值不同即可 type:返回值类型,默认的是dispatcher
result
跳转页面: 转发dispacher 重定向redirect
相应请求: redirectAction
字节流: stream
修改login.jsp页面,增加验证码输入框和图片
验证码:<input id="code" name="code" type="text"><img src="image.do"><br/>
修改struts.xml配置文件,增加image对应的action
<!--生成验证码--> <action name="image" class="imageAction"> <result type="stream"> <param name="inputName">image</param> </result> </action>
增加ImageAction.java文件,生成验证码
@Controller public class ImageAction { @Getter @Setter public InputStream image; public String execute() throws IOException { //画布 // BufferedImage bufferedImage = new BufferedImage(50, 30, BufferedImage.TYPE_INT_RGB); // //画笔 // Graphics graphics = bufferedImage.createGraphics(); // //设置颜色 // graphics.setColor(Color.red); // //起始位置,终止位置,图片内容 // graphics.drawString("java26", 0, 30); // // ByteArrayOutputStream bout = new ByteArrayOutputStream(); // //图片工具类,将内容输出为图片格式 // ImageIO.write(bufferedImage, "png", bout); // // //将outputSteam转换为inputStream 通过字节转换 // byte[] s = bout.toByteArray(); // ByteArrayInputStream bin = new ByteArrayInputStream(s); // // image = bin; return "success"; } }
验证码 工具包utis
ValidateCode
ValidateCode vc = new ValidateCode(); image = vc.getInputStreamImge(60, 30, 1, 1);
验证码验证
json: json(需要单独导包设置)
验证码验证
修改login.jsp页面,增加一个提示区域 导入jquery文件 生成ajax
<span id="vcode"></span>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript"> $(function () { $("#code").blur(function () { var code = $("#code").val().trim(); if(code == ""){ $("#vcode").html("不能为空"); $(":submit").attr("disabled","disabled"); }else{ $.ajax({ url:"${pageContext.request.contextPath }/user/checkCode", type:"post", dataType:"json", data:{"code":code}, success:function (result) { if(result.status == 0){ $("#vcode").html("验证码正确"); $(":submit").removeAttr("disabled"); }else { $("#vcode").html("验证码错误"); $(":submit").attr("disabled", "disabled"); } } }) } }); }); </script>
导入json包
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-json-plugin</artifactId> <version>2.5.16</version> </dependency>
修改struts.xml配置文件,增加校验验证码的action
<!--<package name="user" extends="struts-default" namespace="/user">--> <package name="user" extends="json-default" namespace="/user"> <!--json-default 中继承了struts-default--> <!--验证码验证--> <action name="checkCode" class="checkCodeAction"> <result name="success" type="json"> <param name="root">传入前台的封装数据的引用</param> </result> </action>
用session获取到验证码的正确结果
增加一个CheckCodeAction.java
@Controller @Data public class CheckCodeAction extends BaseAction { public String code; ResultStatus rs = new ResultStatus(); public String execute(){ //获取系统生成的验证码--正确的 String scode = session.get("scode").toString(); //比较系统生成的验证码和用户输入验证码是否匹配code if (code.equalsIgnoreCase(scode)) {//不分区大小写 rs.setStatus(0); rs.setMsg("验证码正确"); }else{ rs.setStatus(2); rs.setMsg("验证码错误"); } return "success"; } }
Interceptor拦截器
struts2内部封装了大量的拦截器,默认的拦截器为:defaultStack,用于登陆拦截,权限认证等
interceptor:拦截器
interceptor-stack:拦截器栈
在用户请求我们的登陆成功页面,如果用户登录,则请求成功,如果用户没登录,则跳转登录页面
拦截单个请求
参考框架自带的拦截器,添加登录拦截器
新建一个LoginInterceptor 实现Interceptor接口 从写intrcept方法
public String intercept(ActionInvocation actionInvocation) throws Exception { //判断用户是否登陆 Map<String, Object> session = ActionContext.getContext().getSession(); String name=session.get("username")!=null? session.get("username").toString():null; //如果没有登陆,则进行页面跳转 if(name==null ||"".equals(name)){ return "NoLogin"; } //如果已经登陆则继续执行其他拦截器 return actionInvocation.invoke(); }
修改struts.xml配置文件
添加定义拦截器,必须在package下一行
<!--定义拦截器--> <interceptors> //创建的拦截类 自定义名 <interceptor name="noLoginInterceptor" class="com.xdl.interceptor.LoginInterceptor"/> </interceptors>
如果想让当前action进行拦截 指向并要处理的返回值类型
指向: action里 <!--<interceptor-ref name="noLoginInterceptor"/>-->
<result name="noLogin" type="redirectAction"> <param name="namespace">/user</param> <param name="actionName">toLogin</param> </result>
拦截全部
参考框架自带的拦截器,添加登录拦截器
新建一个LoginInterceptor 实现Interceptor接口 从写intrcept方法
public String intercept(ActionInvocation actionInvocation) throws Exception { //判断用户是否登陆 Map<String, Object> session = ActionContext.getContext().getSession(); String name=session.get("username")!=null? session.get("username").toString():null; //如果没有登陆,则进行页面跳转 if(name==null ||"".equals(name)){ return "NoLogin"; } //如果已经登陆则继续执行其他拦截器 return actionInvocation.invoke(); }
定义一个package 继承struts-default
//随便写(要被原package继承) //继承原package的 //可以写可以不写 <package name="inteceptor-default" extends="struts-default" namespace="/inteceptor"> <!--定义拦截器--> <interceptors> <interceptor name="noLoginInterceptor" class="com.xdl.interceptor.LoginInterceptor"/> //接收参数,定义拦截器栈 先走自己的再走默认的 <interceptor-stack name="interceptor-stack"> <interceptor-ref name="noLoginInterceptor"/> <interceptor-ref name="defaultStack"> <interceptor-stack> </interceptors> <global-results>//全局results <result name="noLogin" type="redirectAction"> <param name="namespace">/user</param> <param name="actionName">toLogin</param> </result> </global-results> </package> ----------------------------------------------------------------------------- <package> <!--当前package下所有的action,都需要经过拦截器 如果只指定某一部分使用在action内部使用 --> <default-interceptor-ref name="interceptor-stack"/>
Struts2注解配置
导包
<!-- Struts2注解包--> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-convention-plugin</artifactId> <version>2.5.16</version> </dependency>
类上面:
@Namespace("/demo") @ParentPackage("interceptor-default")
方法上
@Action(value="hello",results={ @Result(name="success",location="/WEB-INF/jsp/hello.jsp") },interceptorRefs={@InterceptorRef("interceptor-stack")})
扩展性差 不推荐使用
Hibernate
关系--对象映射的中间件,属于开源ORM框架,是我们业务逻辑层中的调用数据库的中间件
hibernate和mybatis区别?
- hibernate学习难度和复杂度,要比mybatis高(了解) - hibernate不需要写sql语句 - hibernate扩展性和移植性比mybatis要强 - hibernate支持分页条件查询,mybatis不支持(插件) - hibernate支持事务管理,mybatis不支持 - hibernate支持缓存(一级缓存、二级缓存、查询缓存)、mybatis没有缓存(setting---cache==true)
环境搭建步骤:
导包
<!--导入hibernate包--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.3.3.Final</version> </dependency>
加载配置文件(数据库类型、数据源、映射文件路径)hibernate.cfg.xml
增加映射文件
如果用标注 不需要添加映射文件
1.在实体类加标注
2.配置文件指向实体类
HQL和SQL区别?
SQL:面向结构的查询 Structured Query Language(结构化) select * from note 或者 SELECT * FROM NOTE HQL:面向对象的查询 hibernate query language(对象化) select userid(实体类中的属性名称) from Note(实体类名)
- HQL是面向对象的查询,SQL是面向结构化的查询 - HQL查询时候对查询属性大小写比较敏感,SQL在查询的时候对属性的大小写依赖于我们的配置 - HQL支持count、sum、avg等,但是HQL不支持类型转换,比如日期转换、字符串转换 - HQL不建议使用left join,而SQL可以无条件的使用 - HQL在做查询的时候,如果是查询所有字段信息,则可以省略select *,直接使用from 实体类名 - HQL在查询的时候,使用的是类名和属性名,SQL查询的时候,使用的表名和字段名 - HQL和SQL在使用上,或者处理业务上,HQL只能进行简单操作,SQL可以进行复杂操作
查询方式
创建一个调用数据库的工具类
/** * *获取数据库连接信息 */ public static Session getSession(){ Configuration configuration = new Configuration(); configuration.configure("hibernate.cfg.xml");//加载hibernate属性配置文件 SessionFactory sessionFactory = configuration.buildSessionFactory();//获取工厂 Session session = sessionFactory.openSession(); return session; }
mysql查询(通过主键)
查询:
@Test public void test1(){ //参数一 :实体类对象--数据表 //参数二:主键对应的值 Session session =HibernateUtils.getSession(); User user=session.get(User.class,4);//查询功能api if(user!=null){ System.out.println(user.getUsername()+" "+user.getPassword()); } session.close(); }
延迟查询
@Test public void test2(){ /** * 延迟查询 调用才会去查询 */ Session session =HibernateUtils.getSession(); session.load(User.class,1L);//延迟加载特性 }
添加数据
@Test public void test3(){ /** * 增加 */ Session session =HibernateUtils.getSession(); User user=new User(11,"abc","haha"); Transaction transaction =session.beginTransaction();//开启事务 session.save(user); transaction.commit();//提交事务 session.close(); }
修改数据
@Test public void test4(){ /** * 修改 */ Session session =HibernateUtils.getSession(); User user=session.get(User.class,11);//先查询出来 user.setPassword("zhendiao");//设置值 session.update(user);//修改 Transaction transaction =session.beginTransaction();//开启事务 transaction.commit();//提交事务 session.close(); }
删除数据
public void test5() { /** * 删除 * 1.先进行数据查询 * 如果数据存在则继续执行删除操作 * 如果数据不存在则不执行删除操作 * 2条sql语句 */ Session session =HibernateUtils.getSession(); User user=new User(); user.setId(11); session.delete(user); Transaction transaction =session.beginTransaction();//开启事务 transaction.commit();//提交事务 session.close(); }
HQL查询(通过实体类查询)
查询所有的数据
/** *批量查询数据 */ @Test public void test1(){ Session session = HibernateUtils.getSession(); String hql = "from Note"; Query query = session.createQuery(hql); List<Note> list = query.list();//遍历查询所有数据 if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext()); } } }
根据条件进行查询
/** * *简单的条件查询 * sql: select * from note where userid = 1 * hql: from Note where userid = 1 * */ @Test public void test2(){ Session session = HibernateUtils.getSession(); //占位符 //jpa风格写法 //两种方式:第一种是使用下表标记,eg: userid = ?0 不推荐使用 //第二种方式:使用字符进行标记:eg:userid = :userid 推荐使用 // String hql = "from Note where userid = ?0 "; String hql = "from Note where userid =:userid "; Query query = session.createQuery(hql); // query.setInteger(0, 1);//hibernate 4版本写法 // query.setParameter(0, 1);// hibernate 5新特性写法 query.setParameter("userid", 1);// 推荐使用 List<Note> list = query.list();//遍历查询所有数据 if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext()); } } }
分页条件
/** *分页查询 * sql: select * from note limit 0,3 / limit 3; * hql:from Note */ @Test public void test3(){ Session session = HibernateUtils.getSession(); String hql = "from Note"; Query query = session.createQuery(hql); query.setFirstResult(6);//数据开始的下标,从0开始 query.setMaxResults(3);//查询数据的条数 List<Note> list = query.list();//遍历查询所有数据 if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext()); } } }
统计个数
/** *统计个数: * sql: select count(*) from note * hql: select count(*) from Note * */ @Test public void test4(){ Session session = HibernateUtils.getSession(); String hql = "select count(*) from User "; Query query = session.createQuery(hql); System.out.println("个数为:" + query.uniqueResult()); }
Criteria查询(多条件复杂查询通过实体类查询)
查询所有的数据
@Test public void test1(){ Session session = HibernateUtils.getSession(); //省略了hql语句 相当于sql语句:select * from note Criteria criteria = session.createCriteria(Note.class);// 过时了,这是4的写法 List<Note> list = criteria.list(); if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext()); } } }
多条件查询
/** *多条件查询 * sql:select * from note where userid = 1 and likeCount > 10 * sql:select * from note where userid = 1 or likeCount > 10 */ @Test public void test2(){ Session session = HibernateUtils.getSession(); Criteria criteria = session.createCriteria(Note.class); // criteria.add(Restrictions.eq("userid", 1));//userid = 1 // criteria.add(Restrictions.gt("likeCount", 10));//likeCount>10 //userid = 1 or likeCount > 10 criteria.add(Restrictions.or(Restrictions.eq("userid", 1), Restrictions.gt("likeCount", 10))); List<Note> list = criteria.list(); if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext() + "----:" + list.get(i).getLikeCount()); } } }
hibernate5新特性写法
/** * *hibernate5新特性写法 * 完全将所有的hql语法设置为jpa风格 * */ @Test public void test3(){ //通过session获取执行容器 //在容器中创建查询query对象 -- 调用API //为了避免重复写sql语句的关键词,from where and or,5版本把这些关键词,全部封装成了特定的API Session session = HibernateUtils.getSession(); //初始化 CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();//执行容器 CriteriaQuery<Note> criteriaQuery = criteriaBuilder.createQuery(Note.class); Root<Note> root = criteriaQuery.from(Note.class);//root中的泛型可写可不写 //业务 -- 查询所有的数据 Query query = session.createQuery(criteriaQuery); List<Note> list = query.list(); if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext()); } } }
NativeSQL查询(原生查询,支持sql语句 多表查询)
/** * *hibernate5新特性写法 *查询所有数据 *直接在sql语句进行操作 */ @Test public void test2(){ Session session = HibernateUtils.getSession(); String sql = "select * from note"; NativeQuery nativeQuery = session.createNativeQuery(sql); nativeQuery.addEntity(Note.class);//查询出来的映射到实体类上 List<Note> list = nativeQuery.list(); if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("内容为:" + list.get(i).getContext()); } } }
主键管理生成策略(自增)
1.sequence 序列
主要用于oracle数据库
2.identity 主键自增
主要用于mysql、SqlServer 主键自增
3.native
自动识别当前数据库的类型 如果数据库为oracle,则默认的ID生成策略为sequence 如果数据库为mysql等,则默认的ID生成策略为identity
4.increment
代表当前数据库表的主键ID,查询数据库ID最大值+1
5.uuid/hilo
采用UUID和hilo的算法,生成一个字符串,当成主键ID
6.assigned
是hibernate默认的主键生成策略,增加set方法
在note.hbm.xml 主键里添加自增
<!--指定生成策略 主键自增 --> <generator class="identity"/>
或者在实体类加标注
@GeneratedValue(strategy = GenerationType.IDENTITY)
Hibernate特性
延迟加载
hibernate中有一些API具有延迟加载的特性,在对象没有调用之前,是不进行事务的(不进行数据库调用),什么时候使用对象,什么时候调用数据库
问题
问题: 如果使用了具有延迟加载特性的API,才会有以下问题:
......no session.....
问题请求:
请求--->filter--->struts.xml--->action--->service-->impl-->dao(查询 note,session就已经关闭了)-->result--->json/jsp
解决:
请求--->filter--->struts.xml--->action--->service-->impl-->dao(查询 note,session不关闭)-->result--->json/jsp
将事务交给spring进行统一管理 需要在web.xml中进行配置,配置一个OpenSessionInViewFilter 注意事项: 1:此filter必须放到web.xml里struts2配置文件之前 2:文件加载顺序问题
<!--增加OpenSessionInViewFilter信息,解决nosession问题--> <filter> <filter-name>nosession</filter-name> <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>nosession</filter-name> <url-pattern>*</url-pattern> </filter-mapping>
缓存(性能优化)
缓存:第一次调用数据接口的时候,是进行数据库的查询,之后,将查询结果放到缓存中,第N+1次如果查询同样条件的数据,则进行缓存查询,不进行数据库调用,减轻数据库的压力,提高用户的体验。
查询同样的条件的数据,才有效
一级缓存
特点:hibernate本身自带的,不需要做任何的配置,就可以生效 session独享
二级缓存
特点:session共享
需要开启 hibernate.cfg.xml配置文件
依赖于cache.xml
需要在增加缓存的数据上面,增加对应的缓存注解
开发步骤:
1.导包hibernate-cache.jar
<!--导入hibernate缓存包--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>5.3.3.Final</version> </dependency>
2.需要增加cache的配置文件xml,数据存放在内存或磁盘中(二进制格式存放)
3.需要在hibernate.cfg配置文件中,进行开启
<!--开启二级缓存--> <property name="hibernate.cache.use_sencond_level_cache">true</property> <property name="hibernate.cache.region.factory_class"> org.hibernate.cache.ehcache.EhCacheRegionFactory </property>
4.在实体对象中,增加缓存注解
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY) //只能读
查询缓存
特点:依赖于二级缓存(如果想使用查询缓存,则必须开启二级缓存)
需要单独开启查询缓存
只需要在查询的结果集中,调用对应的api即可
开发步骤:
service实现类: //查询缓存api:true,则代表将list数据存放到缓存中 hibernateTemplate.setCacheQueries(true); List<Note> list = (List<Note>) hibernateTemplate.findByCriteria(detachedCriteria);
持久化(session)
数据状态
临时状态
可以被JVM进行垃圾回收
持久化状态
不能更直接被JVM回收,可以先变成其它两种状态之后,才会进行垃圾回收
游离状态
可以被JVM进行垃圾回收
Spring+Hibernate整合
整合步骤:
导包
spring、hibernate、整合包spring-orm.jar mysql驱动包,连接池,spring连接数据源的jdbc包
<dependencies> <!--导入hibernate包--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.3.3.Final</version> </dependency> <!--导入数据库mysql驱动包,连接池--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.24</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--导入spring框架包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.9.RELEASE</version> </dependency> <!--导入spring连接数据源的jdbc包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.9.RELEASE</version> </dependency> <!--导入hibernate和spring的整合包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.0.8.RELEASE</version> </dependency> </dependencies>
加载spring的配置文件applicationContext.xml 扫描包、jdbc属性文件、数据源、连接池、引用hibernateTemplate、开启事务、sessionFactory、注解驱动
serivce实现类注入 hibernateTemplate
SSH框架搭建步骤总结
参考
Struts2框架搭建
导包
- struts2-core.jar
配置启动容器web.xml
- filter控制器 - 请求后缀(默认的是空和action,修改为:*)
增加struts.xml
- package(name:模块名称相同,extends=“struts-default”,namespace="/模块名称") - action - name:请求名称(不需要命名空间和后缀) - class:接口处理类 - method:接口中请求的处理方法,execute - result - name:方法返回值,默认是success - type:返回值类型 - dispatcher:默认 - redirectAction - stream - json(需要单独导包---package--extends=“json-default”) - param - name:inputName---stream - root---json
Spring框架搭建
导包
(bean\context\ioc\core\jdbc.....)
配置启动容器web.xml
- context-param---配置文件路径 - listener --- 自动装配
增加spring配置文件applicationContext.xml
通用信息 - 扫描包(service\dao) - 引用属性文件 - 配置数据源 - 配置连接池 - 配置ORM配置文件 - 开启事务管理、注解驱动 - AOP:面向切面 - 事务管理、日志框架、读写分离(数据库)、缓存 - 可以引用第三方配置文件
整合Struts2和Spring
导包
struts-spring-plugin.jar
修改struts.xml中class信息,修改为ioc容器中bean--id - Action.java类名,第一个字母小写 - 需要在java文件中,类名上面,增加@Controller注解
Hibernate框架搭建
导包
hibernate-core.jar
增加hibernate.cfg.xml配置文件
- 方言(数据库类型) - 数据库连接信息 - 用户名 - 密码 - url - 驱动 - mapper标签(resource--xml,class---entity) - 配置展示sql语句信息(打印控制台、格式化) - 开启二级、查询缓存功能 //增加xxxx.hbm.xml(数据库-实体的关系映射文件)
将hibernate和spring框架进行整合
导包spring-orm.jar
修改spring配置文件applicationContext.xml
hibernateTemplate - sessionFactory - hibernate事务 - 注解驱动
StringUtils.isNotBlank() 判断是不是不等于空
关于多表联合查询
多对一(返回对象)
添加实体类,并在hibernate.cfg.xml添加映射
<mapping class="cn.xdl.entity.Userxq"></mapping>
在主表实体类添加
//optional:默认为true,则为左连接,false:右连接 @ManyToOne//多对一 @OneToMany一对多 //referencedColumnName:匹配主表的关联字段名称 @JoinColumn(name = "userid")//关联哪个字段 public Userxq usersq;//副表的实体类
前端${主表.附表.字段}
一对多(返回list)
如上
在副表实体类添加
副表: @OneToMany// @OneToMany一对多 @JoinColumn(name = "userid")//关联哪个字段 public List<User> user;//副表的实体类
${主表.附表.副表定义的主表返回list}
异常问题
org.hibernate.MappingException: Repeated column in mapping for entity: com.xdl.entity.Note column: userid (should be mapped with insert="false" update="false")
原因: 1:两个表的关联字段名称不一致 2:如果一致 删除主表实体类外键字段 解决: 1:如果两个表的关联字段一致,则只需要注释掉外键字段即可 @JoinColumn(name = "userid",insertable = false,updatable = false) //表示外键id不允许被操作
Win下Nginx+Tomcat集群
nginx 负载均衡代理服务器(今天只使用,后面进行详解)
搭建步骤
准备至少2份应用服务器tomcat(版本是8.0或者8.5) 将SSH项目部署到这两份tomcat中 单独启动每一台tomcat 可以成功单独访问每一台tomcat 修改nginx的配置文件nginx.cnf 增加应用服务器的配置信息 启动nginx(因为学生端有伽卡,所以建议使用cmd命令启动,不建议双击启动) 访问nginx(其实就是访问到项目了)
tom负载均衡 upstream localhost { server 127.0.0.1:8888 weight=2; server 127.0.0.1:8188 weight=2; }
具体细节 同一台电脑上,同时启动两个tomcat,则需要: 不需要配置tomcat环境变量 修改tomcat的3个端口号 在启动tomcat的时候,可以清除缓存和日志文件 为了验证是通过nginx来访问tomcat的不同服务器,则可以在其中一台tomcat中,将前端页面的某一个标志进行修改,验证访问无误
Session共享解决方案(session复制)
集群模式下,必须要实现session(用户登录)共享
session共享的实现方式,常见的有两种: 第一种:使用tomcat自带的机制(session复制),可以实现session共享 前提: tomcat必须在同一台服务器或者IP段内(tomcat之间可以共享访问)
步骤:
1:修改每一台tomcat的配置文件server.xml
将文件中如下配置: <Engine name="Catalina" defaultHost="localhost"> 修改为:(jvmRoute值不相同即可) <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
将<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>从注释中移除到外面,使其生效即可
3:重启tomcat
4:通过以上配置,可以实现tomcat的session复制功能,但是,如果还没实现,则应该是tomcat版本问题,需要额外的在添加如下配置 需要在项目的web.xml中,增加<distributable/>标签 此标签必须在<display-name>之后,其他配置之前
第二种:使用redis服务器,来实现session共享(项目中讲解、使用)