首页 文章 精选 留言 我的

精选列表

搜索[javaee],共384篇文章
优秀的个人博客,低调大师

JavaEE Servlet 并发问题

Java servlet容器/ Web服务器通常是多线程的。 为了确保servlet是线程安全的,必须遵循以下基本规则: servlet service()方法不应该访问任何成员变量,除非这些成员变量本身是线程安全的。 servlet service()不应该重新分配成员变量,因为这可能会影响在service()方法内执行的其他线程。如果您确实需要重新分配一个成员变量,请确保这是在一个同步块内完成的。 对线程不了解的可以看我的文集: java并发学习笔录 做深一步的了解。这里就不多介绍变量和线程安全的问题。 下面是一个图表,说明了上面提到的servlet并发规则/问题。 红色框表示您的servlet的service()方法应该小心访问的状态(变量)。 image.png

优秀的个人博客,低调大师

如何配置IntelliJ IDEA发布JavaEE项目?

一、以war的形式运行项目 步骤1 新建或者导入项目后,选择File菜单-》Project Structure...,如下图: 步骤2 配置项目类型,名字可以自定义: 说明:这里的Artifact如果没有配置好的话,配置Tomcat时没有对应的Artifact时会报错—— warnotfoundforthewebmodule. 步骤3 配置Tomcat (1)编辑配置 (2)配置详情 这里的artifact就是之前步骤2里配置的那个,选择它,删除多余的build选项。 (3)注意事项:配置实时编译,不需要重启Tomcat 注意刚刚Tomcat中的VM配置为: 菜单-》setting勾选自动编译项目: 此时运行项目就能够自动在浏览器打开对应项目首页了。 二、补充 报错:Cannot compile Groovy files: no Groovy library is defined for module 'xx' 解决方法:在setting中的Resource patterns输入框中去除groovy后缀名。如下图: 2. 搜索字符串、文件的快捷方式 Windows下连续按下shift键。

优秀的个人博客,低调大师

JavaEE基础(05):过滤器、监听器、拦截器,应用详解

本文源码:GitHub·点这里 || GitEE·点这里 一、Listener监听器 1、概念简介 JavaWeb三大组件:Servlet,Listener,Filter。监听器就是指在应用程序中监听相关对象状态变化的组件。 2、事件源对象 指被监听对象。 ServletContext ServletContextListener生命周期监听,它有两个方法,出生时调用contextInitialized(),销毁时调用contextDestroyed(); ServletContextAttributeListener属性监听,它有三个方法,添加属性attributeAdded(),替换属性attributeReplaced(),移除属性时attributeRemoved()。 HttpSession HttpSessionListener生命周期监听:它有两个方法,出生时调用sessionCreated(),销毁时调用sessionDestroyed(); HttpSessioniAttributeListener属性监听:它有三个方法,添加属性attributeAdded(),替换属性attributeReplaced(),移除属性attributeRemoved()。 ServletRequest ServletRequestListener生命周期监听:它有两个方法,出生时调用requestInitialized(),销毁时调用requestDestroyed(); ServletRequestAttributeListener属性监听:它有三个方法,添加属性attributeAdded(),替换属性attributeReplaced(),移除属性attributeRemoved()。 3、编码案例 相关监听器 TheContextListener public class TheContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("初始化:TheContextListener"); ServletContext servletContext = servletContextEvent.getServletContext() ; servletContext.setAttribute("author","cicada"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("销毁:TheContextListener"); } } TheRequestListener public class TheRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent servletRequestEvent) { System.out.println("初始化:TheRequestListener"); } @Override public void requestInitialized(ServletRequestEvent servletRequestEvent) { System.out.println("销毁:TheRequestListener"); } } TheSessionListener public class TheSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("初始化:TheSessionListener"); } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { System.out.println("销毁:TheSessionListener"); } } RequestAttributeListener public class RequestAttributeListener implements ServletRequestAttributeListener { @Override public void attributeAdded(ServletRequestAttributeEvent evt) { System.out.println("Request添加属性:"+evt.getName()+";"+evt.getValue()); } @Override public void attributeRemoved(ServletRequestAttributeEvent evt) { System.out.println("Request移除属性:"+evt.getName()+";"+evt.getValue()); } @Override public void attributeReplaced(ServletRequestAttributeEvent evt) { System.out.println("Request替换属性:"+evt.getName()+";"+evt.getValue()); } } web.xml配置文件 <!-- 监听器相关配置 --> <listener> <listener-class>com.node05.servlet.listener.TheContextListener</listener-class> </listener> <listener> <listener-class>com.node05.servlet.listener.TheSessionListener</listener-class> </listener> <listener> <listener-class>com.node05.servlet.listener.TheRequestListener</listener-class> </listener> <listener> <listener-class>com.node05.servlet.listener.RequestAttributeListener</listener-class> </listener> <session-config> <!-- 设置session失效时间为1分钟 --> <session-timeout>1</session-timeout> </session-config> 测试接口 public class ListenerServletImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); // 1、获取TheContextListener初始化数据 ServletContext servletContext = this.getServletContext() ; String author = String.valueOf(servletContext.getAttribute("author")) ; System.out.println("TheContextListener Author:"+author); // 2、Request属性设置 request.setAttribute("mood","smile"); request.setAttribute("mood","agitated"); // 3、Session创建,1分钟失效,调用销毁 HttpSession session = request.getSession(true) ; session.setAttribute("casually","casually"); response.getWriter().print("Hello:Listener"); } } 二、Filter过滤器 1、过滤器简介 客户端请求Servlet时,先执行相关Filter,如果Filter通过,则继承执行请求的Servlet;如果Filter不通过,则不会执行用户请求的Servlet。过滤器可以动态地拦截请求和响应。 2、Filter接口 Filter接口定义了三个核心方法。 init() 应用程序启动时,服务器实例化Filter对象,并调用其init方法,读取web.xml配置,完成对象的初始化加载。 doFilter() 实际的过滤操作,请求达到服务器时,Servlet容器将先调用过滤器的doFilter方法。 destroy() 容器在销毁过滤器前调用该方法,释放过滤器占用的资源。 3、编码案例 编写过滤器 public class ThePrintLogFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { String myName = filterConfig.getInitParameter("myName") ; System.out.println("myName:"+myName); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest ; HttpServletResponse response = (HttpServletResponse)servletResponse ; String name = request.getParameter("name") ; if (!name.equals("cicada")){ response.getWriter().print("User Error !"); return ; } chain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { System.out.println("ThePrintLogFilter destroy()"); } } web.xml配置文件 <!-- 过滤器相关配置 --> <filter> <filter-name>thePrintLogFilter</filter-name> <filter-class>com.node05.servlet.filter.ThePrintLogFilter</filter-class> <init-param> <param-name>myName</param-name> <param-value>cicada</param-value> </init-param> </filter> <filter-mapping> <filter-name>thePrintLogFilter</filter-name> <url-pattern>/filterServletImpl</url-pattern> </filter-mapping> 测试接口 public class FilterServletImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); response.getWriter().print("Hello:Filter"); } } 三、Interceptor拦截器 Spring框架中的拦截器Interceptor类似于Servlet中的过滤器Filter,主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。请求转发不执行拦截、过滤;重定向执行拦截和过滤。 ---END---

优秀的个人博客,低调大师

JavaEE基础(06):Servlet整合C3P0数据库连接池

本文源码:GitHub·点这里 || GitEE·点这里 一、C3P0连接池 1、C3P0简介 C3P0是一个开源的JDBC连接池,应用程序根据C3P0配置来初始化数据库连接,可以自动回收空闲连接的功能。 2、核心依赖 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>${c3p0.version}</version> </dependency> 3、配置文件 配置文件位置:放在resources目录下,这样C3P0组件会自动加载该配置。 <?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <!-- 核心参数配置 --> <property name="jdbcUrl">jdbc:mysql://localhost:3306/servlet-jdbc</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="user">root</property> <property name="password">123</property> <!-- 池参数配置 --> <property name="acquireIncrement">3</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">2</property> <property name="maxPoolSize">10</property> </default-config> </c3p0-config> 4、编写工具类 该工具类用来获取数据库连接,和释放相关连接。 public class C3P0Pool { private static DataSource dataSource = new ComboPooledDataSource(); public static DataSource getDataSource() { return dataSource ; } /** * 获取连接 */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } /** * 释放连接 */ public static void close(ResultSet resultSet, PreparedStatement pst, Connection connection) { if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (pst != null) { try { pst.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } 二、数据操作封装 1、新增数据 public class UserJdbcInsert { public static void insertUser (UserInfo userInfo){ try { Connection connection = C3P0Pool.getConnection(); String sql = "INSERT INTO user_info (user_name,user_age) VALUES (?,?)" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,userInfo.getUserName()); statement.setString(2,userInfo.getUserAge().toString()); statement.execute() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } public static void batchInsertUser (List<UserInfo> userInfoList){ try { Connection connection = C3P0Pool.getConnection(); String sql = "INSERT INTO user_info (user_name,user_age) VALUES (?,?)" ; PreparedStatement statement = connection.prepareStatement(sql); for (UserInfo userInfo:userInfoList){ statement.setString(1,userInfo.getUserName()); statement.setString(2,userInfo.getUserAge().toString()); statement.addBatch(); } statement.executeBatch() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } } 2、查询数据 public class UserJdbcQuery { public static UserInfo queryUser (String userName){ UserInfo userInfo = null ; try { Connection connection = C3P0Pool.getConnection(); String sql = "SELECT * FROM user_info WHERE user_name=?" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,userName); ResultSet resultSet = statement.executeQuery() ; while (resultSet.next()){ int id = resultSet.getInt("id"); String name = resultSet.getString("user_name"); int age = resultSet.getInt("user_age"); System.out.println("ID:"+id+";name:"+name+";age:"+age); userInfo = new UserInfo(name,age) ; } C3P0Pool.close(resultSet, statement, connection); } catch (Exception e) { e.printStackTrace(); } return userInfo ; } } 3、更新数据 public class UserJdbcUpdate { public static void updateUser (String name,Integer age,Integer id){ try { Connection connection = C3P0Pool.getConnection(); String sql = "UPDATE user_info SET user_name=?,user_age=? WHERE id=?" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,name); statement.setInt(2,age); statement.setInt(3,id); statement.executeUpdate() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } } 4、删除数据 public class UserJdbcDelete { public static void deleteUser (Integer id){ try { Connection connection = C3P0Pool.getConnection(); String sql = "DELETE FROM user_info WHERE id=?" ; PreparedStatement statement = connection.prepareStatement(sql); statement.setInt(1,id); statement.executeUpdate() ; C3P0Pool.close(null, statement, connection); } catch (Exception e) { e.printStackTrace(); } } } 三、Servlet接口 public class JdbcServletImpl extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userName = request.getParameter("userName") ; UserInfo userInfo = UserJdbcQuery.queryUser(userName) ; response.setContentType("text/html;charset=utf-8"); response.getWriter().print("用户信息:"+userInfo); } } 测试访问: http://localhost:6003/jdbcServletImpl?userName=LiSi 页面打印: 用户信息:UserInfo{userName='LiSi', userAge=22}

优秀的个人博客,低调大师

【JAVA秒会技术之秒杀面试官】JavaEE常见面试题(一)

1.Struts2中,Action通过什么方式获取用户从页面输入的数据,又是通过什么方法把数据传给视图层显示的? 答:(1)Action从页面获取数据的方式有三种: ①通过Action属性接收参数;(例:${pageContext.request.contextPath}/***.action? id=xxxx) ②通过域模型获取参数;(例:ServletActionContext.getRequest().getParameter(arg0)) ③通过模型驱动获取参数(例:extends ModelDriven) (2)Action将数据存入值栈(Value Stack)中,视图可以通过表达式语言(EL)从值栈中获取; 2.阐述Struts2中的Action如何编写,是否采用单例? 答:(1)Struts2的Action有三种写法: ①POJO类——无继承无实现; ②实现Action接口,重写execute()方法; ③继承ActionSupport(常用); (2)Action没有像Servlet一样,使用单实例多线程的工作方式,很明显,每一个Action要接收不同用户的请求参数,这就意味着Action是有状态的,因此在设计上使用了,每一个请求对应一个Action的处理方式,所以是多例的。 3.Struts2中,Action并没有直接收到用户的请求,那它为什么可以处理用户的请求?又凭什么知道一个请求到底交给哪一个Action来处理? 答:(1)Struts2的核心过滤器收到用户的请求后,会对用户的请求进行简单的预处理(如解析、封装参数),然后通过反射来创建Action实例,并调用Action中指定的方法来处理用户请求。 (2)通知具体调用哪个Action来处理请求的方式,有两种: ①利用配置文件,Struts.xml中配置的标签来确定; ②利用约定,Struts2中可以使用约定(convention)插件。例如:约定xxx总是对应XxxAction,这是对约定优于配置理念的践行; 4.简述Struts2异常处理机制? 5.简述拦截器的工作原理? 答:在Struts2中,可以实现Interceptor接口或继承AbstractInterceptor类,来自定义拦截器。 ①接口中的init()方法,在拦截器被创建后立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化; ②每拦截一个请求,intercept()方法就会被调用一次; ③destory()方法将在拦截器销毁之前被调用。 6.谈一下拦截器和过滤器的区别? 答:拦截器和过滤器都可以用来实现横切关注功能,其区别主要在于: ①拦截器是基于JAVA反射机制的,而过滤器是基于函数回调的 ②过滤器依赖于Servlet容器,而拦截器不依赖于Servlet容器 ③拦截器只能对Action请求起作用(Action中的方法),而过滤器可以对几乎所有的请求起作用(CSS JSP JS) 7.谈一下你的项目选择Struts2的理由? 答:①Action是POJO类,没有依赖Servlet API,具有良好的可测试性; ②强大的拦截器,简化了开发的复杂度; ③支持多种表现层技术:JSP、Freemarker等; ④灵活的验证方式; ⑤国际化(I18N)支持 ⑥声明式异常管理; ⑦通过JSON插件简化Ajax; ⑧通过Spring插件跟Spring整合; 8.Struts2中如何访问HttpServletRequest、HttpSession和ServletContext三个域对象? 答:有两种方式: ①通过ServletActionContext的方法获得; ②通过ServletRequestAware、SessionAware和ServletContextAware接口注入。 9.Struts2中的默认包struts-default有什么作用? 答:它定义了Struts2内部的众多拦截器和Result类型,而Struts2很多核心的功能是通过这些内置的拦截器实现,如:从请求中把参数封装到action、文件上传和数据校验等等,都是通过拦截器实现的。在Struts2的配置文件中,自定义的包,继承了struts-default包,就可以使用Struts2为我们提供这些功能。 10.简述值栈的原理和生命周期? 答:Value-Stack贯穿整个Action的生命周期,保存在request作用域中,所以它和request的生命周期一样。当Struts2接受一个请求时,会创建ActionContext、Value-Stack和Action对象,然后把Action存放进Value-Stack,所以Action的实例变量可以通过OGNL访问。由于Action是多实例的,和使用单例的Servlet不同,每个Action都有一个对应的Value-Stack,Value-Stack存放的数据类型是该Action的实例,以及该Action中的实例变量,Action对象默认保存在栈顶。 11.SessionFactory是线程安全的吗?Session是线程安全的吗?两个线程能共享一个Session吗? 答:(1)SessionFactory对应Hibernate的一个数据存储的概念,它是线程安全的,可以被多个线程并发访问。SessionFactory一般只会在启动的时候构建。对于应用程序,最好将SessionFactory通过单例的模式进行封装以便于访问。 (2)Session是一个轻量级非线程安全的对象(线程间不能共享Session),它表示与数据库进行交互的一个工作单元。Session是由SessionFactory创建的,在任务完成之后会被关闭。Session是持久层服务对外提供的主要接口。Session会延迟获取数据库连接(也就是在需要的时候才会获取)。为了避免创建太多的session,可以使用TreadLocal来获取当前的session,无论你调用多少次getCurrentSession()方法,返回的都是同一个session。 12.Session的load和get方法区别是什么? 答:①如果没有找到符合条件的记录,get方法返回null值,而load方法会抛出异常; ②get方法直接返回实体类对象,load方法返回实体类对象的代理; ③在Hibernate3之前,get方法只在一级缓存(内部缓存)中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据的读取;load方法则可以充分利用二级缓存中现有数据,进行延迟加载。当然从Hibernate3开始,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的; 简单的是,对于load()方法,hibernate认为该数据在数据库中一定存在,可以放心的使用代理来实现延迟加载,如果没有数据,就会抛出异常,而通过get()方法去取数据,是可以不存在的。 13.阐述Session加载实体对象的过程? 答:①Session在调用数据查询功能之前,首先会在缓存中进行查询,在一级缓存中,通过实体类型和主键进行查询,如果一级缓存查找命中且数据状态合法,则直接返回; ②如果一级缓存没有命中,接下来Session会在当前NonExists记录(相当于一个查询黑名单,如果出现重复的无效查询可以迅速判断,从而提升性能)中进行查询,如果NonExists中存在同样的查询条件,则返回null; ③对于load方法,如果一级缓存查询失败,则查询二级缓存,如果二级缓存命中则直接返回; ④如果之前的查询都未命中,则发出sql语句,如果查询未发现对应的记录,则此次查询添加到Session的NonExists中加以记录,并返回null; ⑤根据映射配置和sql语句,得到ResultSet,并创建对应的实体对象; ⑥将对象纳入Session(一级缓存)管理; ⑦执行拦截器的onload方法(如果有对应的拦截器); ⑧将数据对象纳入二级缓存; ⑨返回数据对象。 14.Query接口的list方法和iterate方法有什么区别? 答:①list()方法返回的每个对象都是完整的(对象中的每个属性都被表中的字段填充上了),list方法无法利用缓存,它对一级缓存只写不读; ②iterate方法可以充分利用一级缓存,它所返回的对象中仅包含了主键值(标识符),只有当你对iterator中的对象进行操作时,Hibernate才会向数据库再次发送SQL语句来获取该对象的属性值; ②list方法不会引起N+1查询问题,而iterate方法会引起N+1查询问题。 15.Hibernate如何实现分页查询? 答:通过Hibernate实现分页查询,开发人员只需要提供HQL语句、查询起始行数(setFirstResult()方法)和最大查询行数(setMaxResult()方法),并调用Query接口的list()方法,Hibernate会自动生成分页查询的SQL语句。 需要免费Java架构学习资料视频请加扣扣群835544715 群内提供免费的学习指导 架构资料 以及免费的解答 不懂得问题都可以在本群提出来 之后还会有职 业生涯规划以及面试指导

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册