这是场景.作为公开许可的开源API的创建者,我的团队创建了一个基于Java的Web用户界面框架(那么还有什么新东西?).为了在Java中保持良好和有条理,我们使用了命名约定org.mygroup.myframework.x的包,其中x是组件,验证器,转换器,实用程序等等(同样,还有什么是新?).
现在,org.mygroup.myframework.foo.Bar类中的某个地方是void doStuff()我需要执行特定于我的框架的逻辑的方法,我需要能够从我的框架中的其他几个地方调用它,例如org. mygroup.myframework.far.Boo.鉴于Boo既不是Bar的子类也不是完全相同的包,所以方法doStuff()必须声明为public才能被Boo调用.
但是,我的框架作为一种工具存在,允许其他开发人员为其客户创建更简单,更优雅的RIA.但是,如果com.yourcompany.yourapplication.YourComponent调用doStuff(),则可能会产生意外和不良后果.我希望永远不会允许这种情况发生. 请注意,Bar包含其他真正公开的方法.
在象牙塔世界中,我们将重写Java语言并将标记化模拟插入到默认访问中,这将允许我们选择的包结构中的任何类访问我的方法,可能类似于:
[org.mygroup.myframework.*] void doStuff() { .... }
Run Code Online (Sandbox Code Playgroud)
其中通配符是指任何以org.mygroup.myframework开头的包可以调用的类,但没有其他人.
鉴于这个世界不存在,我们还有什么其他好的选择?
请注意,这是由现实生活场景推动的; 名称已被更改以保护有罪.存在一个真正的框架,在其整个Javadoc中,人们会发现公共方法被评论为"这种方法是内部的MYFRAMEWORK而不是其公共API的一部分.请不要打电话!!!!!!" 一些研究表明这些方法是从框架内的其他地方调用的.
事实上,我是一名使用相关框架的开发人员.虽然我们的应用程序已经部署并且取得了成功,但我的团队遇到了很多挑战,我们希望说服我们的老板再也不要使用这个框架了.我们希望通过对框架开发人员做出的糟糕设计决策的深思熟虑的演示来做到这一点,而不仅仅是作为一个咆哮.这个问题将是我们观点中的一个(但有几个),但我们无法理解我们如何以不同的方式完成它.在我的工作场所已经有了一些热烈的讨论,所以我想知道世界其他地方会怎么想.
更新:到目前为止,对两个回答者没有冒犯,但我认为你错过了这个标记,或者我没有表达好.无论哪种方式,我都可以尝试照亮事物.尽可能简单地说,框架的开发人员应该如何重构以下内容.请注意,这是一个非常粗略的例子.
package org.mygroup.myframework.foo;
public class Bar {
/** Adds a Bar component to application UI */
public boolean addComponentHTML() {
// Code that adds the HTML for a Bar component to a UI screen
// returns true if successful
// I need users of my framework to be able to call this method, so
// they can actually add …Run Code Online (Sandbox Code Playgroud) 似乎每次我学习一个新平台时,我都必须重新解决同样的老问题:使用Ajax更改另一个下拉列表时,在一个下拉列表中更新选项.这次框架是Wicket.
我有两个实体,我称之为Foo和Bar,每个Foo都有一个类别,这是Foo内部的枚举.此外,存在具有重载find()方法的FooDAO :no-arg版本返回DB中的所有Foo,或者具有类型Foo的参数"filter"的版本,其返回非空值中的所有Foo匹配过滤器.
客户希望在创建新条形图时将Foos与条形图关联,但在添加条形图之前按类别过滤Foos.假设已经存在少数Foo,每个都有一个类别.用户进入创建栏页面和添加新Foo的部分:下拉列表A列出类别,并且在选择类别时,下拉列表B应该通过Ajax更新显示该类别中可用Foo的列表.注意,没有选择类别,下拉列表B应该显示所有可用的Foo.
我的HTML看起来有点像这样:
<form wicket:id="createBarForm">
<div>
<label>Category</label>
<select wicket:id="category">
</select>
</div>
<div>
<label>Available Foo(s)</label>
<select class="xlarge" wicket:id="selectedFoo">
</select>
</div>
<button style="float:right;">Add</button>
<!-- and more Bar related fields -->
</form>
Run Code Online (Sandbox Code Playgroud)
(该按钮最终将获得自己的id和行为,但现在焦点在于列表.)
这是Java端(在页面的构造函数方法中):
createBarForm = new Form<Bar>("createBarForm",
new CompoundPropertyModel<Bar>());
final List<Foo> availableFoo = fooDao.find();
final FormComponent<Foo> selectedFoo =
new DropDownChoice<Foo>("selectedFoo",
Model.of(new TechnologyFoo()), availableFoo);
Foo.Category categoryStandin = null;
final FormComponent<Foo.Category> fooCategory =
new DropDownChoice<Foo.Category>
("fooCategory", Model.of(categoryStandin),
Arrays.asList(Foo.Category.values()));
fooCategory.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
@Override
protected …Run Code Online (Sandbox Code Playgroud) 我需要在更改为文本框时触发ajax更新,文本框是一个<p:autoComplete>组件.我观察到如果用户选择手动键入文本,则事件是更改,而如果用户单击自动完成的其中一个建议,则事件为itemSelect.所以我<p:ajax>在输入中添加了两个子节点,每个子节点调用相同的方法并具有相同的更新列表,但是一个具有event="change"和另一个event="itemSelect".
但是,我现在发现一些奇怪的东西.例如,在正常服务器模式下,我打开了我的页面并输入"12".自动完成提供"1233"和"1234"作为建议.我点击了"1233",似乎什么也没发生.我再次点击,其他一切都填写完毕.
在调试器中使用事件处理程序上的断点重复此操作,我可以看到在第一次单击后,值为"12",在第二次单击时,它变为"1233".
通过切换两个不同的评论<p:ajax>我可以看到不同的后果.如果没有"更改",则在用户选择自动完成建议时从不调用处理程序,如果没有"itemSelect",则在用户手动键入时不会调用处理程序.但是对于他们两个,有两个电话,我相信会有关于双击的投诉.
一些伪代码,对于那些喜欢,首先是xhtml:
<p:autoComplete id="itemId" value="#{myBacker.myBean.itemNumber}"
required="true" completeMethod="#{myBacker.idAutoComplete}">
<p:ajax event="itemSelect" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
<p:ajax event="change" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
</p:autoComplete>
<h:panelGroup id="beanDetails">
<h:panelGroup rendered="#{not empty myBacker.myBean.institutionName}">
<h:outputText value="#{myBacker.myBean.institutionName}" />
<!-- Continues with address, phone, etc.. -->
</h:panelGroup>
</h:panelGroup>
Run Code Online (Sandbox Code Playgroud)
然后是Java支持bean代码:
public void idChangeEventListener() {
myBean = myDAO.getDetails(myBean);
// another couple of init-type method calls
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试设计一个小型CRUD工具,到目前为止,每个方面(Rich Faces UI和Managed Beans,验证,mySQL数据库等)都很顺利,但不是myBatis.
我对myBatis比较陌生,并且保持用户指南和API近在咫尺,但仍有一些东西对我来说不会合在一起,一个是对涉及多个IN参数的过程的任何调用.这是一个例子:
这来自DB设置脚本:
create procedure MY_FOO_PROC (IN valA VARCHAR(15), IN valB CHAR(1))
begin
select blah from blah where blah = valA and blah = valB etc.;
end
Run Code Online (Sandbox Code Playgroud)
这来自MyMapper.java:
public interface MyMapper {
List<MyFooClass> getProgress (
@Param("valA") String valueA, @Param("valB") String valueB);
}
Run Code Online (Sandbox Code Playgroud)
这来自MyMapper.xml:
<select id="getProgress" parameterType="map"
resultMap="MyFooMap" statementType="CALLABLE">
{ call MY_FOO_PROC (
#{valA, mode=IN, jdbcType=VARCHAR}
#{valB, mode=IN, jdbcType=CHAR}
)}
</select>
Run Code Online (Sandbox Code Playgroud)
最后来自我的DAO课程:
public static List<MyFooClass>
doGetProgress (String valueA, String valueB) {
SqlSession session = MyBatisConnectionFactory.getInstance().getSqlSessionFactory().openSession();
EsparMapper mapper = …Run Code Online (Sandbox Code Playgroud) 这是我的表格的视觉效果:
+---------+------------+-------------------+ | Header1 | Header2 | Header3 | +---------+------------+-------------------+ | Row A | Input A | Calc'ed output A | | Row B | Input B | Calc'ed output B | | etc.. | etc.. | etc.. | +---------+------------+-------------------+ | Total: Total calc'ed output | +------------------------------------------+
精简代码:
<p:dataTable id="myTable" value="#{myBean.someList}"
var="currentItem">
<p:column headerText="Header1">
<h:outputText value="#{currentItem.name}" />
</p:column>
<p:column headerText="Header2">
<pe:inputNumber value="#{currentItem.inputVal}">
<p:ajax event="change" listener="#{myBean.changeListener}"
update="outputVal outputTotal" />
</pe:inputNumber>
</p:column>
<p:column headerText="Header3">
<h:outputText id="outputVal" value="#{currentItem.outputVal}" />
</p:column>
<f:facet name="footer">
Total: …Run Code Online (Sandbox Code Playgroud) 我们的应用程序使用Wicket前端,使用Spring注入来加载我们的DOA并管理事务.
我们发现我们的几个用户双击链接/按钮,这会以某种方式破坏Spring注入,以便后续调用whateverDao.doStuff(obj)抛出NPE此应用程序在我们客户的内部网络上运行,而目前,我们礼貌地要求客户在他们的团队中宣传单击所有功能.但很明显,这对他们来说正在成为一个问题.
常见用例涉及"搜索"屏幕,其中显示当前系统中所有Foo对象的列表,如果需要,可以通过搜索参数对其进行过滤,当单击项目时,用户将被带到该特定Foo的详细页面,最初处于只读模式.接下来,用户可以单击角落中的"编辑"按钮以切换到编辑模式.然后,用户可能会进行一些更改并单击"保存"(或者可能单击"删除"以删除该项目.)
此方案涉及最多三个步骤的DAO调用:1.在搜索页面上,单击项目时,加载该项目的基本详细信息.2.在只读模式的详细信息页面上,单击编辑时,加载该项目的完整详细信息.3A.在编辑模式下的详细信息页面上,单击"保存"时,将保留更改.3B.在编辑模式下的详细信息页面上,单击删除时,删除.
在任何这些情况下,如果用户双击上一步,则下一步产生错误.重现性约为33%,浏览器和操作系统之间存在一些差异.
有关防止这种情况的见解?
在下面的示例中,BasePage是Wicket的WebPage的自定义扩展,包含我们的菜单和其他常见页面元素,PageType是CREATE,EDIT和READ_ONLY详细信息的枚举.
搜索页面的示例代码(显示Java,HTML是您所期望的):
import org.apache.wicket.spring.injection.annot.SpringBean;
// and other imports
public class FooManagerPage extends BasePage {
@SpringBean
private transient FooDao fooDao;
public FooManagerPage() {
SortableDataProvider<Foo> provider = new SortableDataProvider<Foo>(fooDao);
add(new FeedbackPanel("feedback");
final Form<Foo> searchFooForm = new Form<Foo>("searchFooForm",
new CompoundPropertyModel<Foo>(new Foo()));
// the form's search parameter's go here
// with a 'search' button that filters table below
add(searchFooForm)
List<IColumn<Foo>> columns = new ArrayList<IColumn<Foo>>();
columns.add(new PropertyColumn<Foo>(Model.of("Name"), "name", "name"));
// a couple other columns here …Run Code Online (Sandbox Code Playgroud) ajax ×2
jsf ×2
primefaces ×2
wicket ×2
autocomplete ×1
dom-events ×1
double-click ×1
java ×1
mybatis ×1
spring ×1
user-input ×1