对java:comp/env的研究 .(转发)

本文详细解析了Java EE环境下通过java:comp/env/和直接.两种方式访问JNDI服务的区别及实现方法,包括配置web.xml、weblogic.xml等文件以映射全局和私有JNDI资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两天研究了一下 context.lookup("java:comp/env/XXX")和直接context.lookup("XXX")的区别

网上关于这两个的文章也很多,但是都说得很难理解,比如什么ENC环境啊什么的,各种概念。

其实说得简单点:context.lookup("java:comp/env/XXX")只能用在J2EE环境,即是如果你自己写一个main函数,想通过context.lookup("java:comp/env/XXX")这样的方式来访问JNDI服务,这是不可能的。
因为:java:comp/env/是一个J2EE环境的定义,说白了就是代表当前J2EE应用的环境,比如你自己项目的Web环境或者是EJB环境,那是不是只要是个Web项目,就能用context.lookup("java:comp/env/XXX")这种方式访问JNDI服务了呢?也不是!!!
使用这样的方式必须做一次 当前应用环境 到 资源名 的映射。
在web.xml文件中有这样的标签:
<resource-env-ref></resource-env-ref> 
<resource-ref></resource-ref>
<ejb-local-ref></ejb-local-ref>
<ejb-ref></ejb-ref>


这些标签就是用来建立当前应用环境到服务器资源的映射的。
有了这样的映射之后,就能采用context.lookup("java:comp/env/XXX")的方式来访问JNDI资源了。


注意:context.lookup("XXX")在任何时候都是有效的,只要XXX确实是一个存在的JNDI名。


举个例子:
用weblogic10的控制台定了了一个oracle数据源,这个数据源的JNDI名称是:adsl,那么只要正确连接上了weblogic(当然需传递URL,用户名和密码还有weblogic的JNDI工厂对象,这不属于该文的讨论范围)在任何地方都能用context.lookup("xxx")得到这个数据源了,但是想通过context.lookup("java:comp/env/jdbc/adsl")访问到这个数据源,就不行了。如果想这样写的话需要做两件事情:
1、确保你的调用程序是一个web项目或者EJB项目,并部署到weblogic上。(例子使用web项目)
2、在web项目的web.xml里面加上如下配置:
<resource-ref> 
<res-ref-name>jdbc/adsl</res-ref-name>
<res-auth>Container</res-auth>
<mapped-name>adsl</mapped-name> <!-- 这个必须和你的全局JNDI数据源名称一样 -->
</resource-ref>


那么你就能在你的web程序里通过context.lookup("java:comp/env/jdbc/adsl")访问到这个数据源了。

关于EJB的访问也类似这样,可以直接访问全局EJB的JNDI名,和可以映射之后从java:comp/env/下进行访问。


以上的讲解有错。。。。。
上面的情况只适用于weblogic和J2EE 2.5的规范下。
一:如果不是J2EE 2.5的规范:那么在你的web项目的web.xml内将根本不会存在<mapped-name>这个标签,那么怎样才能映射全局JNDI资源到你的项目呢?
以weblogic为例,你需要在和web.xml同级的目录下建立:weblogic.xml文件,在该文件里面写上:
<weblogic-web-app> 
<resource-description>
<res-ref-name>jdbc/adsl</res-ref-name>
<jndi-name>adsl</jndi-name><!-- 这个就是全局JNDI资源名 -->
</resource-description>
</weblogic-web-app>

然后你仍然需要在web.xml里面配置上:
<resource-ref> 
<res-ref-name>jdbc/adsl</res-ref-name>
<res-auth>Container</res-auth>
</resource-ref>


这样你才可以在你的程序里面通过context.lookup("java:comp/env/jdbc/adsl")访问到这个数据源。
这个是weblogic.xml的官方帮助文档:http://edocs.weblogicfans.net/wls/docs92/webapp/weblogic_xml.html

二:如果不是使用weblogic,可参见这篇文章:http://blog.youkuaiyun.com/lovingprince/article/details/6577920
其实各种不同的J2EE容器,都用不同的配置方式,以我目前的测试来看,weblogic似乎不能配置“私有的JNDI资源”,就是不能配置自己项目单独的JNDI资源(这只是我的观点,我目前没发现怎么在weblogic里面配置私有JNDI资源)
但是研究tomcat6之后发现,tomcat可以配置 全局JNDI 和私有JNDI(注意这里说的Tomcat6):
!!!首先想要说明的是Tomcat的配置不需要修改web.xml里面的任何内容!!!!!
!!!Tomcat的全局JNDI资源不能直接访问,必须有java:comp/env/前缀!!!!!!
全局的JNDI配置在server.xml里面的<GlobalNamingResources>标签里面添加如下配置:
 <Resource name="jdbc/test" 
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1/test"
username="root"
password="root"
maxActive="20"
maxIdle="10"
maxWait="-1"/>


然后某一个项目想要引用这个全局的JNDI,就需要在项目的META-INF下面建立context.xml文件,在里面写上:
<?xml version="1.0" encoding="UTF-8"?> 
<Context>
<ResourceLink name="jdbc/test" global="jdbc/test" type="javax.sql.DataSource"/>
</Context>


这样就可以在程序里面通过context.lookup("java:comp/env/jdbc/test")进行访问了。

私有的JNDI有三种方式可以配置:
1、可以直接在server.xml里面的<Host>节点下添加如下配置:
<Context path="/test_tomcat6_jndi"> 
<Resource name="jdbc/test"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1/test"
username="root"
password="root"
maxActive="20"
maxIdle="10"
maxWait="-1"/>
</Context>


这样就可以直接在程序中通过context.lookup("java:comp/env/jdbc/test")访问了,需要注意的是path="/test_tomcat6_jndi",这个名字必须和你的项目名称相同,而且不能少了那个斜杠,而且你的项目是通过拷贝文件夹到webapps下面的方式进行的部署。

2、 也可以在conf/context.xml里面增加如下配置:
     <Resource name="jdbc/test" 
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1/test"
username="root"
password="root"
maxActive="20"
maxIdle="10"
maxWait="-1"/>

这样就可以直接在程序中通过context.lookup("java:comp/env/jdbc/test")访问了

3、还可以在项目的WebRoot下面的META-INF文件夹下面创建context.xml文件,再在context.xml文件里面写上
<?xml version="1.0" encoding="UTF-8"?> 
<Context>
<Resource name="jdbc/test"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1/test"
username="root"
password="root"
maxActive="20"
maxIdle="10"
maxWait="-1"/>
</Context>
这样就可以直接在程序中通过context.lookup("java:comp/env/jdbc/test")访问了

你可以发现的是:以上的Tomcat6中的配置不管是全局还是局部,都没有修改项目的web.xml文件,但是仍然建议在web.xml中进行引用,主要是为了项目的迁移,因为有的服务器需要在web.xml中进行声明!

总之:各种服务器有时候确实有比较大的出入,特别是感觉J2EE中类似<resource-ref>这样的一些标签仍然不是很理解。
根据-- 创建数据库 CREATE DATABASE TicketSalesSystem; GO USE TicketSalesSystem; GO -- 创建票价类型表 CREATE TABLE TicketType ( TypeID INT PRIMARY KEY IDENTITY(1,1), TypeName NVARCHAR(20) NOT NULL CHECK (TypeName IN ('老年', '小孩', '成人', '团体')), BasePrice DECIMAL(10,2) NOT NULL, DiscountRate DECIMAL(5,2) DEFAULT 1.0, Description NVARCHAR(255), CreatedAt DATETIME DEFAULT GETDATE(), UpdatedAt DATETIME DEFAULT GETDATE() ); GO -- 创建营业员表 CREATE TABLE Salesperson ( SalespersonID INT PRIMARY KEY IDENTITY(1,1), EmployeeID NVARCHAR(20) UNIQUE NOT NULL, Name NVARCHAR(50) NOT NULL, Password NVARCHAR(100) NOT NULL, Role NVARCHAR(20) DEFAULT 'staff' CHECK (Role IN ('admin', 'staff')), IsActive BIT DEFAULT 1, CreatedAt DATETIME DEFAULT GETDATE(), LastLogin DATETIME NULL ); GO -- 创建门票销售表 CREATE TABLE TicketSale ( SaleID INT PRIMARY KEY IDENTITY(1,1), TypeID INT NOT NULL, SalespersonID INT NOT NULL, Quantity INT NOT NULL CHECK (Quantity > 0), UnitPrice DECIMAL(10,2) NOT NULL, TotalAmount DECIMAL(10,2) NOT NULL, SaleTime DATETIME DEFAULT GETDATE(), IsRefund BIT DEFAULT 0, CONSTRAINT FK_TicketSale_TicketType FOREIGN KEY (TypeID) REFERENCES TicketType(TypeID), CONSTRAINT FK_TicketSale_Salesperson FOREIGN KEY (SalespersonID) REFERENCES Salesperson(SalespersonID) ); GO -- 创建退票记录表 CREATE TABLE RefundRecord ( RefundID INT PRIMARY KEY IDENTITY(1,1), SaleID INT NOT NULL, RefundQuantity INT NOT NULL CHECK (RefundQuantity > 0), RefundAmount DECIMAL(10,2) NOT NULL, RefundTime DATETIME DEFAULT GETDATE(), Reason NVARCHAR(255), CONSTRAINT FK_RefundRecord_TicketSale FOREIGN KEY (SaleID) REFERENCES TicketSale(SaleID) ); GO -- 创建操作日志表 CREATE TABLE AuditLog ( LogID INT PRIMARY KEY IDENTITY(1,1), UserID INT NOT NULL, ActionType NVARCHAR(20) NOT NULL, ActionDetails NVARCHAR(500) NOT NULL, ActionTime DATETIME DEFAULT GETDATE(), CONSTRAINT FK_AuditLog_Salesperson FOREIGN KEY (UserID) REFERENCES Salesperson(SalespersonID) ); GO -- 创建索引优化查询性能 CREATE INDEX IX_TicketSale_SaleTime ON TicketSale(SaleTime); CREATE INDEX IX_TicketSale_Salesperson ON TicketSale(SalespersonID); CREATE INDEX IX_TicketSale_Type ON TicketSale(TypeID); CREATE INDEX IX_RefundRecord_SaleID ON RefundRecord(SaleID); CREATE INDEX IX_AuditLog_ActionTime ON AuditLog(ActionTime); GO -- 存储过程1: 统计指定日期的门票销售情况 CREATE PROCEDURE sp_DailySalesSummary @TargetDate DATE AS BEGIN SELECT TT.TypeName AS 票种类型, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS JOIN TicketType TT ON TS.TypeID = TT.TypeID WHERE CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 GROUP BY TT.TypeName ORDER BY 总收入 DESC; END; GO -- 存储过程2: 统计指定月份的门票销售情况 CREATE PROCEDURE sp_MonthlySalesSummary @Year INT, @Month INT AS BEGIN SELECT TT.TypeName AS 票种类型, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS JOIN TicketType TT ON TS.TypeID = TT.TypeID WHERE YEAR(TS.SaleTime) = @Year AND MONTH(TS.SaleTime) = @Month AND TS.IsRefund = 0 GROUP BY TT.TypeName ORDER BY 总收入 DESC; END; GO -- 存储过程3: 统计指定日期各种价格的门票销售情况 CREATE PROCEDURE sp_DailySalesByPrice @TargetDate DATE AS BEGIN SELECT TS.UnitPrice AS 销售单价, COUNT(TS.SaleID) AS 销售笔数, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS WHERE CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 GROUP BY TS.UnitPrice ORDER BY TS.UnitPrice DESC; END; GO -- 存储过程4: 统计指定营业员指定日期的收费情况 CREATE PROCEDURE sp_SalespersonDailySummary @SalespersonID INT, @TargetDate DATE AS BEGIN SELECT SP.Name AS 营业员姓名, COUNT(TS.SaleID) AS 交易笔数, SUM(TS.Quantity) AS 总票数, SUM(TS.TotalAmount) AS 总收入 FROM TicketSale TS JOIN Salesperson SP ON TS.SalespersonID = SP.SalespersonID WHERE SP.SalespersonID = @SalespersonID AND CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 GROUP BY SP.Name; -- 详细交易列表 SELECT TT.TypeName AS 票种类型, TS.Quantity AS 数量, TS.UnitPrice AS 单价, TS.TotalAmount AS 金额, FORMAT(TS.SaleTime, 'HH:mm:ss') AS 销售时间 FROM TicketSale TS JOIN TicketType TT ON TS.TypeID = TT.TypeID WHERE TS.SalespersonID = @SalespersonID AND CAST(TS.SaleTime AS DATE) = @TargetDate AND TS.IsRefund = 0 ORDER BY TS.SaleTime DESC; END; GO -- 存储过程5: 处理门票销售 CREATE PROCEDURE sp_ProcessTicketSale @TypeID INT, @SalespersonID INT, @Quantity INT, @SaleID INT OUTPUT AS BEGIN BEGIN TRY BEGIN TRANSACTION; DECLARE @UnitPrice DECIMAL(10,2); DECLARE @TotalAmount DECIMAL(10,2); -- 获取票价信息 SELECT @UnitPrice = BasePrice * DiscountRate FROM TicketType WHERE TypeID = @TypeID; IF @UnitPrice IS NULL RAISERROR('无效的票种ID', 16, 1); -- 计算总金额 SET @TotalAmount = @UnitPrice * @Quantity; -- 插入销售记录 INSERT INTO TicketSale ( TypeID, SalespersonID, Quantity, UnitPrice, TotalAmount ) VALUES ( @TypeID, @SalespersonID, @Quantity, @UnitPrice, @TotalAmount ); SET @SaleID = SCOPE_IDENTITY(); -- 记录操作日志 INSERT INTO AuditLog (UserID, ActionType, ActionDetails) VALUES ( @SalespersonID, 'SALE', CONCAT('销售门票: 票种ID=', @TypeID, ', 数量=', @Quantity, ', 金额=', @TotalAmount) ); COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(); RAISERROR(@ErrorMessage, 16, 1); END CATCH END; GO -- 存储过程6: 处理门票退票 CREATE PROCEDURE sp_ProcessTicketRefund @SaleID INT, @RefundQuantity INT, @Reason NVARCHAR(255), @RefundID INT OUTPUT AS BEGIN BEGIN TRY BEGIN TRANSACTION; DECLARE @MaxQuantity INT; DECLARE @UnitPrice DECIMAL(10,2); DECLARE @RefundAmount DECIMAL(10,2); -- 获取原始销售信息 SELECT @MaxQuantity = Quantity, @UnitPrice = UnitPrice FROM TicketSale WHERE SaleID = @SaleID; IF @MaxQuantity IS NULL RAISERROR('无效的销售ID', 16, 1); -- 检查可退票数量 DECLARE @AlreadyRefunded INT = 0; SELECT @AlreadyRefunded = ISNULL(SUM(RefundQuantity), 0) FROM RefundRecord WHERE SaleID = @SaleID; DECLARE @Remaining INT = @MaxQuantity - @AlreadyRefunded; IF @RefundQuantity > @Remaining RAISERROR('退票数量超过可退数量', 16, 1); -- 计算退款金额 SET @RefundAmount = @UnitPrice * @RefundQuantity; -- 插入退票记录 INSERT INTO RefundRecord ( SaleID, RefundQuantity, RefundAmount, Reason ) VALUES ( @SaleID, @RefundQuantity, @RefundAmount, @Reason ); SET @RefundID = SCOPE_IDENTITY(); -- 更新销售记录状态 IF @RefundQuantity = @Remaining UPDATE TicketSale SET IsRefund = 1 WHERE SaleID = @SaleID; -- 记录操作日志 DECLARE @SalespersonID INT = (SELECT SalespersonID FROM TicketSale WHERE SaleID = @SaleID); INSERT INTO AuditLog (UserID, ActionType, ActionDetails) VALUES ( @SalespersonID, 'REFUND', CONCAT('退票处理: 销售ID=', @SaleID, ', 数量=', @RefundQuantity, ', 金额=', @RefundAmount) ); COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE(); RAISERROR(@ErrorMessage, 16, 1); END CATCH END; GO -- 存储过程7: 获取所有有效票种 CREATE PROCEDURE sp_GetActiveTicketTypes AS BEGIN SELECT TypeID, TypeName, BasePrice, DiscountRate, ROUND(BasePrice * DiscountRate, 2) AS ActualPrice, Description FROM TicketType ORDER BY TypeName; END; GO -- 存储过程8: 添加新票种 CREATE PROCEDURE sp_AddTicketType @TypeName NVARCHAR(20), @BasePrice DECIMAL(10,2), @DiscountRate DECIMAL(5,2) = 1.0, @Description NVARCHAR(255) = NULL AS BEGIN IF NOT @TypeName IN ('老年', '小孩', '成人', '团体') RAISERROR('无效的票种名称', 16, 1); INSERT INTO TicketType ( TypeName, BasePrice, DiscountRate, Description ) VALUES ( @TypeName, @BasePrice, @DiscountRate, @Description ); RETURN SCOPE_IDENTITY(); END; GO -- 存储过程9: 营业员登录验证 CREATE PROCEDURE sp_VerifySalespersonLogin @EmployeeID NVARCHAR(20), @Password NVARCHAR(100), @IsValid BIT OUTPUT AS BEGIN SET @IsValid = 0; IF EXISTS ( SELECT 1 FROM Salesperson WHERE EmployeeID = @EmployeeID AND Password = @Password AND IsActive = 1 ) BEGIN SET @IsValid = 1; -- 更新最后登录时间 UPDATE Salesperson SET LastLogin = GETDATE() WHERE EmployeeID = @EmployeeID; END END; GO -- 存储过程10: 月度销售趋势分析 CREATE PROCEDURE sp_MonthlySalesTrend @Year INT AS BEGIN SELECT MONTH(SaleTime) AS 月份, SUM(TotalAmount) AS 月收入, COUNT(SaleID) AS 交易笔数, SUM(Quantity) AS 总票数 FROM TicketSale WHERE YEAR(SaleTime) = @Year AND IsRefund = 0 GROUP BY MONTH(SaleTime) ORDER BY 月份; END; GO -- 创建触发器: 更新票种时自动更新更新时间戳 CREATE TRIGGER trg_UpdateTicketTypeTimestamp ON TicketType AFTER UPDATE AS BEGIN UPDATE TicketType SET UpdatedAt = GETDATE() WHERE TypeID IN (SELECT TypeID FROM inserted); END; GO -- 创建触发器: 退票后更新销售记录状态 CREATE TRIGGER trg_AfterRefund ON RefundRecord AFTER INSERT AS BEGIN SET NOCOUNT ON; UPDATE TS SET TS.IsRefund = CASE WHEN (TS.Quantity - i.RefundQuantity) <= 0 THEN 1 ELSE 0 END FROM TicketSale TS INNER JOIN inserted i ON TS.SaleID = i.SaleID; END; GO -- 创建视图: 销售明细视图 CREATE VIEW vw_SaleDetails AS SELECT TS.SaleID, TS.SaleTime, SP.Name AS SalespersonName, TT.TypeName, TS.Quantity, TS.UnitPrice, TS.TotalAmount, CASE WHEN TS.IsRefund = 1 THEN '已退票' ELSE '有效' END AS Status, ISNULL(RR.RefundQuantity, 0) AS RefundedQuantity FROM TicketSale TS JOIN Salesperson SP ON TS.SalespersonID = SP.SalespersonID JOIN TicketType TT ON TS.TypeID = TT.TypeID LEFT JOIN ( SELECT SaleID, SUM(RefundQuantity) AS RefundQuantity FROM RefundRecord GROUP BY SaleID ) RR ON TS.SaleID = RR.SaleID; GO -- 插入初始数据 INSERT INTO TicketType (TypeName, BasePrice, DiscountRate, Description) VALUES ('成人', 100.00, 1.00, '标准成人票'), ('小孩', 50.00, 1.00, '1.2-1.5米儿童票'), ('老年', 60.00, 1.00, '65岁以上老人票'), ('团体', 80.00, 0.90, '10人及以上团体票'); GO INSERT INTO Salesperson (EmployeeID, Name, Password, Role) VALUES ('admin001', '管理员', 'admin123', 'admin'), ('staff001', '张三', 'staff123', 'staff'), ('staff002', '李四', 'staff456', 'staff'); GO -- 插入示例销售记录 DECLARE @SaleID INT; EXEC sp_ProcessTicketSale 1, 2, 2, @SaleID OUTPUT; EXEC sp_ProcessTicketSale 2, 2, 1, @SaleID OUTPUT; EXEC sp_ProcessTicketSale 3, 3, 3, @SaleID OUTPUT; EXEC sp_ProcessTicketSale 4, 3, 10, @SaleID OUTPUT; GO -- 插入示例退票记录 DECLARE @RefundID INT; EXEC sp_ProcessTicketRefund 1, 1, '行程变更', @RefundID OUTPUT; GO这个数据库代码对3. 模型层实现 (model) 位置:src/main/java/com/ticketsystem/model/ 功能:数据库表对应的JavaBean 关键类: TicketType.java Salesperson.java TicketSale.java RefundRecord.java DailySales.java (报表DTO) 示例:TicketSale.java java public class TicketSale { private int saleId; private int typeId; private int salespersonId; private int quantity; private BigDecimal unitPrice; private BigDecimal totalAmount; private Timestamp saleTime; private boolean isRefund; // Getters/Setters } 4. 数据访问层实现 (dao) 位置:src/main/java/com/ticketsystem/dao/ 功能:封装数据库操作,调用存储过程 关键接口: TicketTypeDAO.java TicketSaleDAO.java RefundDAO.java ReportDAO.java 示例:ReportDAOImpl.java java public class ReportDAOImpl implements ReportDAO { private static final String DAILY_SALES_PROC = "{call sp_DailySalesSummary(?)}"; @Override public List<DailySales> getDailySales(LocalDate date) throws SQLException { List<DailySales> results = new ArrayList<>(); try (Connection conn = DatabaseUtil.getConnection(); CallableStatement stmt = conn.prepareCall(DAILY_SALES_PROC)) { stmt.setDate(1, Date.valueOf(date)); stmt.execute(); try (ResultSet rs = stmt.getResultSet()) { while (rs.next()) { DailySales sales = new DailySales(); sales.setTypeName(rs.getString("TypeName")); sales.setTotalTickets(rs.getInt("TotalTickets")); sales.setTotalIncome(rs.getBigDecimal("TotalIncome")); results.add(sales); } } } return results; } } 5. 服务层实现 (service) 位置:src/main/java/com/ticketsystem/service/ 功能:业务逻辑处理 关键类: TicketService.java (售票/退票) ReportService.java (报表) AuthService.java (认证) 示例:TicketServiceImpl.java java public class TicketServiceImpl implements TicketService { private final TicketSaleDAO saleDAO = new TicketSaleDAOImpl(); private final TicketTypeDAO typeDAO = new TicketTypeDAOImpl(); @Override public String processSale(int typeId, int quantity, int salespersonId) { try { TicketType type = typeDAO.getById(typeId); BigDecimal unitPrice = type.getBasePrice().multiply(type.getDiscountRate()); BigDecimal totalAmount = unitPrice.multiply(BigDecimal.valueOf(quantity)); TicketSale sale = new TicketSale(); sale.setTypeId(typeId); sale.setSalespersonId(salespersonId); sale.setQuantity(quantity); sale.setUnitPrice(unitPrice); sale.setTotalAmount(totalAmount); saleDAO.addSale(sale); return "销售成功! 交易号: " + sale.getSaleId(); } catch (SQLException e) { return "销售失败: " + e.getMessage(); } } } 6. 控制器层实现 (servlet) 位置:src/main/java/com/ticketsystem/servlet/ 功能:处理HTTP请求 关键类: TicketSaleServlet.java RefundServlet.java ReportServlet.java AuthServlet.java 示例:TicketSaleServlet.java java @WebServlet("/api/sale") public class TicketSaleServlet extends HttpServlet { private final TicketService ticketService = new TicketServiceImpl(); private final Gson gson = new Gson(); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { JsonObject data = gson.fromJson(request.getReader(), JsonObject.class); int typeId = data.get("typeId").getAsInt(); int quantity = data.get("quantity").getAsInt(); HttpSession session = request.getSession(); Salesperson user = (Salesperson) session.getAttribute("user"); String result = ticketService.processSale(typeId, quantity, user.getSalespersonId()); response.setContentType("application/json"); response.getWriter().write(gson.toJson(Map.of("message", result))); } } 7. 安全过滤器实现 (filter) 位置:src/main/java/com/ticketsystem/filter/ 功能:请求拦截与认证 关键类:AuthFilter.java java @WebFilter("/*") public class AuthFilter implements Filter { private static final Set<String> ALLOWED_PATHS = Set.of( "/login.html", "/api/login", "/assets/" ); public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String path = request.getRequestURI().substring(request.getContextPath().length()); boolean allowed = ALLOWED_PATHS.stream().anyMatch(path::startsWith); if (allowed || request.getSession().getAttribute("user") != null) { chain.doFilter(request, response); } else { response.sendRedirect(request.getContextPath() + "/login.html"); } } } 8. 工具类实现 (util) 位置:src/main/java/com/ticketsystem/util/ 功能:通用工具 关键类: DatabaseUtil.java (数据库连接) JsonUtil.java (JSON处理) PasswordUtil.java (密码加密) 示例:DatabaseUtil.java java public class DatabaseUtil { public static Connection getConnection() throws SQLException, NamingException { Context initContext = new InitialContext(); Context envContext = (Context) initContext.lookup("java:/comp/env"); DataSource ds = (DataSource) envContext.lookup("jdbc/TicketDB"); return ds.getConnection(); } }进行重新生成,要求给出完整代码,使用编译器为idea
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值