22 Aralık 2021 Çarşamba

Wildfly Elytron Security System - SSL

Giriş
Önce bir self signed sertifika üretiriz. Şöyle yaparız
keytool 
  -genkeypair 
  -alias wildfly 
  -keyalg RSA 
  -sigalg SHA256withRSA 
  -validity 365 
  -keysize 2048 
  -keypass jboss@123 
  -storepass jboss@123 
  -dname "CN=developer.jboss.org, C=IN" 
  -ext san=dns:developers.redhat.org,dns:developers.wildfly.org 
  -keystore wildfly.jks
Elytron içindeki adımlar şöyle
1. key store yaratma
2. key manager yaratma
3. server-ssl-context yaratma

Undertow içindeki adımlar şöyle
1. https-listener Elytron içinde yeni yaratılan server-ssl-context'i kullanacak şekilde ayarlanır
2. management interface Elytron içinde yeni yaratılan server-ssl-context'i kullanacak şekilde ayarlanır

1. key store yaratma
Sertifikayı yani wildfly.jks dosyasını $WildFly_Home/ssl dizinine taşırız. Elytron'a dahil etmek için  şöyle yaparız
/subsystem=elytron/key-store=wildflyKS:add(type=JKS,
path="${jboss.home.dir}/ssl/wildfly.jks",credential-reference={clear-text=jboss@123})
2. key manager yaratma
Şöyle yaparız
/subsystem=elytron/key-manager=wildflyKM:add(algorithm=SunX509,
key-store=wildflyKS,credential-reference={clear-text=jboss@123})
3. server-ssl-context yaratma
Şöyle yaparız
/subsystem=elytron/server-ssl-context=wildlfySSC:add(key-manager=wildflyKM,
protocols=[TLSv1.2])
1. https-listener ayarlama
Şöyle yaparız
batch
/subsystem=undertow/server=default-server/https-listener=https:undefine-attribute(
name=security-realm)
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(
name=ssl-context,value=wildlfySSC)
run-batch
2. management interface ayarlama
Şöyle yaparız
/core-service=management/management-interface=http-interface:write-attribute(
name=secure-socket-binding,value=management-https)
/core-service=management/management-interface=http-interface:write-attribute(
name=ssl-context,value=wildflySSC)

21 Aralık 2021 Salı

Wildfly PicketBox

Gradle
Şu satırı dahil ederiz
implementation 'org.wildfly:wildfly-ejb3:8.2.1.Final'
PicketBox artık kullanılmamasına rağmen yeni Wildfly sürümlerinde derleme esnasında hata sebep oluyor. Hata şöyle
[WARNING] The POM for org.picketbox:picketbox:jar:5.0.3.Final-redhat-00006 is missing, 
no dependency information available
Gradle ile düzeltmek için şöyle yaptım. Yani yeni bir repository eklemek gerekti. Benzer bir açıklama da burada
repositories {      
  jcenter()      
  maven { url 'http://maven.repository.redhat.com/ga' }      
}  
SecurityContextAssociation Sınıfı
Şu satırı dahil ederiz
import org.jboss.security.SecurityContextAssociation;
getPrincipal metodu
Şöyle yaparız
String user = SecurityContextAssociation.getPrincipal().getName();
setOutgoingRunAs metodu
Şöyle yaparız
SecurityContextAssociation..getSecurityContext().setOutgoingRunAs(runAsIdentity);


19 Aralık 2021 Pazar

Wildfly Elytron Security System

Giriş
Açıklaması şöyle. Yani PicketBox'ın yerine geldi.
Elytron is a new security framework that ships with WildFly version 10 and Red Hat JBoss Enterprise Application Platform (EAP) 7.1. This project is a complete replacement of PicketBox and JAAS. 
Elytron İle Neler Yapılabilir
Açıklaması şöyle
- SSL/TLS
- Secure credential storage
- Authentication
- Authorization
Tüm komutlar jboss-cli ile çalıştırılır. Şöyle yaparız
$WildFly_Home/bin/jboss-cli 
SSL/TLS

Authorization
- Bir permission yaratılır
- Bu permission bir kullanıcıya atanır. Buna permission mapping deniliyor

Wildfly ile iki tane permission hazır geliyor. Bunlar
1. login-permission
2. default-permissions

Yeni permission yaratmanın  söz dizimi şöyle
/subsystem=elytron/permission-set=MyPermissionSetName:add(
  permissions=[{class-name="...", module="...", target-name="...", action="..."}...])
Açıklaması şöyle
In the above command, permissions consists of a set of permissions, where each permission can have the following attributes:
- class-name - the fully qualified class name of the permission (this is the only permission attribute that is required)
- module - the optional module to use to load the permission
- target-name - the optional target name to pass to the permission as it is constructed
- action - the optional action to pass to the permission as it is constructed

After a permission-set has been created, it can be referenced when creating a permission mapper in order to assign permissions to an identity.
Örnek
Şöyle yaparız
/subsystem=elytron/permission-set=run-as-principal-permission:add(
 permissions=[{class-name="org.wildfly.security.auth.permission.RunAsPrincipalPermission",
 target-name="*"}])
XML çıktısı şöyle olur. Burada "urn:wildfly:elytron:3.0" kullanılan sürüme göre değişir.
<subsystem xmlns="urn:wildfly:elytron:3.0" ...>
  ...
  <permission-sets>
    <permission-set name="login-permission">
      <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
    </permission-set>
    <permission-set name="default-permissions">
      <permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission"         module="org.wildfly.extension.batch.jberet" target-name="*"/>
      <permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission"         module="org.wildfly.transaction.client"/>
      <permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
    </permission-set>
    <permission-set name="run-as-principal-permission">
      <permission class-name="org.wildfly.security.auth.permission.RunAsPrincipalPermission" target-name="*"/>
    </permission-set>
  </permission-sets>
  ...
</subsystem>
Şimdi permission'ları kullanıcıya atamak lazım. Yani permission mapping gerekiyor. Şöyle yaparız. Burada anonymous ve server1 isimli kullanıcılara permission atanıyor
/subsystem=elytron/simple-permission-mapper=my-simple-permission-mapper:add(
  permission-mappings=
  [
    {
      principals=["anonymous"]
    },
    {
      principals=
	["server1"], 
          permission-sets=[
            {permission-set=login-permission}, 
            {permission-set=default-permissions}, 
            {permission-set=run-as-principal-permission}]
    },
    {
      match-all=true,
        permission-sets=
	   [
	     {permission-set=login-permission}, 
             {permission-set=default-permissions}
	   ]
    }
 ]
)
Açıklaması şöyle
The above command creates a simple permission mapper that:
- Assigns no permissions to an anonymous user
-Assigns the permissions referenced in the login-permission, default-permissions, and run-as-principal-  permission permission sets to the server1 user
- Assigns the permissions referenced in the login-permission and default-permissions permission sets to all other users
XML çıktısı şöyle olur
<subsystem xmlns="urn:wildfly:elytron:3.0" ...>
  ...
  <mappers>
    ...
    <simple-permission-mapper name="my-simple-permission-mapper">
      <permission-mapping>
        <principal name="anonymous"/>
      </permission-mapping>
      <permission-mapping>
        <principal name="server1"/>
          <permission-set name="login-permission"/>
          <permission-set name="default-permissions"/>
          <permission-set name="run-as-principal-permission"/>
        </permission-mapping>
        <permission-mapping match-all="true">
          <permission-set name="login-permission"/>
          <permission-set name="default-permissions"/>
        </permission-mapping>
      </simple-permission-mapper>
      ...
  </mappers>
  ...
</subsystem>











17 Aralık 2021 Cuma

Jakarta EE @EJB Anotasyonu

Giriş
Şu satırı dahil ederiz
import javax.ejb.EJB;
Açıklaması şöyle
If none of the other mechanisms are used, then the javadoc says the @EJB will target an EJB in the same application that implements the target type if there is only one.
beanName Alanı
Açıklaması şöyle
The beanName can be used to specify the target EJB if the EJB is located in the same application as your component
lookup Alanı
Açıklaması şöyle
In EJB 3.1, the lookup is a portable way to specify a JNDI string of the target.
mappedName Alanı - Kullanmayın
Açıklaması şöyle
The mappedName is a non-portable, vendor-specific string (even though it's part of the standard!) that somehow identifies the target.
name Alanı
Açıklama yaz


Jakarta EE @Resource Anotasyonu - JNDI Lookup İçindir

Giriş
Şu satırı dahil ederiz
import javax.annotation.Resource;
Açıklaması şöyle
The @Resource annotation is required for injecting certain (JNDI) resources that are not available to @Inject, such as DataSource and the EJB TimerService
lookup Alanı
Örnek
Şöyle yaparız
@Resource(lookup = "java:/jdbc/books-database")
private DataSource dataSource;
name Alanı
Örnek
Şöyle yaparız
// field injection
@Resource(name = "java:comp/DefaultDataSource")
DataSource ds;

// method injection
@Resource(name = "java:comp/DefaultDataSource")
void setDataSource(DataSource ds) { ... }
Örnek
Şöyle yaparız
@Resource(name = "jdbc/MyDataSource")
private DataSource dataSource;

Portable JNDI Syntax

Giriş
3 tane portable JNDI ön eki var. Bunlar şöyle
1. java:global
  Remote EJB İçindir. Uygulamalar aynı veya farklı bilgisayarda olabilir
2. java:app
  Aynı EAR içindeki farkı modüllerdeki Local EJB içindir
3. java:module
  Aynı module içindeki Local EJB içindir
1. java:global
Şeklen şöyle. global içinde ear yani application ismi kullanılıyor
java:global[/application name]/module name/enterprise bean name[/interface name]
Açıklaması şöyle
java:global is a namespace that's global for the entire application server, which includes other EAR modules (which are considered to be different applications).
3. java:app
Şeklen şöyle. Burada modul ismi kullanılıyor
java:app[/module name]/enterprise bean name[/interface name]
Açıklaması şöyle
java:global is a namespace that's global for the entire application server, which includes other EAR modules (which are considered to be different applications).
3. java:module
Şeklen şöyle
java:module/enterprise bean name/[interface name]
4. java:comp/env
Açıklaması şöyle
java:comp/env is populated with names declared by the app.
Yani kendi uygulamamda mantıksa bir JNDI ismi yaratırım. Bu mantıksal ismi de gerçek bir fiziksel kaynağa yönlendiririm. Böylece kendi uygulamamı değiştirmeden daha farklı bir fiziksel JNDI kaynağıma erişebilmemi sağlarım. web.xml'deki <resource-ref> veya @Resource bu işe yarar

Wildfly JNDI

Giriş
Runtime/JNDI ekranı açılır. Bu ekranda JNDI Tree gösterilir. Applications düğümü altında benim uygulamalarımın yarattığı JNDI nesneleri vardır.

Her jar dosyası "java:app" altında kendi ismiyle bir düğüm açar.
Bu jar içindeki her EJB de iki tane JNDI girdisi yaratır. Bunlara short binding ve long binding deniliyor. Açıklaması şöyle
The EJB container performs two default classic bindings for each interface (business, remote home, or local home) or no-interface view on each enterprise bean. These two classic bindings are referred to here as the views of the interface or no-interface short binding and long binding. The short binding uses just the package-qualified Java class name of the interface or no-interface view, while the long binding uses the component ID of the enterprise bean as an extra qualifier prior to the package-qualified interface or no-interface view class name, with a hash or number sign (# symbol) between the component ID and the interface or no-interface view class name.

You can think of the difference between the two forms as being analogous to a short TCP/IP host name (just the machine name) versus a long host name (machine name with domain name prepended to it).

For example, the short and long default classic bindings for an interface or no-interface view might be
com.mycompany.AccountService and AccountApp/module1.jar/ServiceBean#com.mycompany.AccountService
respectively.
Yani short binding için şöyle. Yani jar ismi + Sınıf ismi
java:app/myjarname/MyEJB
Long binding için şöyle. Yani short binding + ünlem + "fully qualified package name"
java:app/myjarname/MyEJB!com.foo.MyEJB
full qualified package name için Java'da  şöyle yaparız
String name = Foo.class.getCanonicalName();




Servlet web.xml İle Spring'i Birleştirme

Giriş
Servlet olarak org.springframework.web.servlet.DispatcherServlet belirtilir

Örnek
Şöyle yaparız
<servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
  </servlet-class>
  <load-on-startup>1</load-on-startup>
  
</servlet>
<servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>
servlet-name olarak ne verdiysek isim + "-servlet.xml" diye bir dosya oluşturulur. Dosyada Spring bean'leri tanımlanır. Bu örnek için xml dosyası şöyledir
spring-servlet.xml
spring-servlet.xml şöyledir. Burada JSP dosyalarının /WEB-INF/jsp altında olduğu belirtiliyor, ayrıca spring component scan yapılıyor. 
<beans ...>

  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
      <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
      <value>.jsp</value>
    </property>
  </bean>
	
  <bean id="multipartResolver" 
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- max upload size in bytes -->
    <property name="maxUploadSize" value="2097152" /> <!-- 2MB -->
         
    <!-- max size of file in memory (in bytes) -->
    <property name="maxInMemorySize" value="10240" /> <!-- 10 kB -->
  </bean>
	
  <context:component-scan base-package="com.nsn.advantage.in.railway.gui.controller" />
  <context:component-scan base-package="com.nsn.advantage.in.railway.gui.batchprocess" />
	
</beans>
Daha da ilkel bir yöntem şöyle. Burada component scan kullanılmadan her bean elle tanımlanıyor. JNDI içinse yine String sabitlerinden faydalanılıyor
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
	    
  <bean id="myHttpController" class="com.foo.MyHttpController" >  
   	<property name="jndiBean" ref="jndiBean" /> 
  </bean>

  <bean id="jndiBean" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" 
      value="#{T(com.foo.MyBeansUtils).SESSION_BEAN_LOCAL_JNDI}" />
  </bean>
	
  <bean id="urlMapAdmin"
    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="urlMap">
      <props>                
        <prop key="/myHttp">myHttpController</prop>      
      </props>
    </property>
  </bean>
   
</beans>





16 Aralık 2021 Perşembe

Servlet @MultipartConfig Anotasyonu - Multipart File Upload İçindir

Giriş
Şu satırı dahil ederiz
import javax.servlet.annotation.MultipartConfig;
Açıklaması şöyle
The simplest approach a developer can take to handle a file upload is to use the Servlet 3.0 Part class, which can process a multipart form element and allow a file to be incrementally saved until it completes the file upload.
Açıklaması şöyle. Bu anotasyon yerine web.xml'de tanımlama yapılabilir.
Use HttpServletRequest.getPart() API in code. You configure it via either the @MultipartConfig annotation and/or the <multipart-config> descriptor element in your WEB-INF/web.xml
Örnek
Şöyle yaparız
@WebServlet(name = "FileUploadServlet", urlPatterns = { "/fileuploadservlet" })
@MultipartConfig(
  fileSizeThreshold = 1024 * 1024 * 1, // 1 MB
  maxFileSize = 1024 * 1024 * 10,      // 10 MB
  maxRequestSize = 1024 * 1024 * 100   // 100 MB
)
//Simple Java File Upload Example
public class FileUploadServlet extends HttpServlet {

  public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
   
    Part filePart = request.getPart("file");
    String fileName = filePart.getSubmittedFileName();
    for (Part part : request.getParts()) {
      part.write("C:\\upload\\" + fileName);
    }
    response.getWriter().print("Sucessfully Java file upload.");
  }
}
Burada getPart("file") çağrısı ile HttpServletRequest isteğindeki şu alana erişiliyor. Buradan dosya ismi alınıyor
Content-Disposition: form-data; name="file"; filename="..."

fileSizeThreshold Alanı
Dosya belirtilen büyüklüğü geçerse diske yazılır.
Örnek
Şöyle yaparız.
@WebServlet(name = "MyServlet", urlPatterns = {"/add"})
@MultipartConfig(fileSizeThreshold = 1024 * 1024 * 2, // 2MB
    maxFileSize = 1024 * 1024 * 10, // 10MB
    maxRequestSize = 1024 * 1024 * 50)
public class MyServlet extends HttpServlet {
...
}

Servlet web.xml Dosyası - Servlet İçin Gerekir

web-app tag
Bu dosyada servlet spec'inden hangisini kullanacağımızı belirtiyoruz.
Örnek
2.5 için şöyle yaparız
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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-app_2_5.xsd"
  version="2.5">
  ...
</web-app>
Örnek
3.0 içinse şöyle yaparız.
<web-app 
  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-app_3_0.xsd"
  version="3.0">
Örnek
3.1 için şöyle yaparız
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
...
</web-app>
context-param tag
Bu parametre uygulama ayağa kalkarken okunuyor  ve ServletContext arayüzüne yerleşiyor. servet/init-param'dan farklı olarak tüm uygulama için geçerli değerleri buraya koymak lazım.

Örnek
Şöyle yaparız.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="..." xmlns="..." xmlns:web="..." 
 xsi:schemaLocation="..." id="WebApp_ID" version="2.5">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring-servlet.xml</param-value>
  </context-param>
  ...
</web-app>
Örnek
Şöyle yaparız
<web-app>
    <context-param>
        <param-name>Country</param-name>
        <param-value>India</param-value>
    </context-param>
    <context-param>
        <param-name>Age</param-name>
        <param-value>24</param-value>
    </context-param>
</web-app>
Erişmek için şöyle yaparız.
getServletContext().getInitParameter("Country");
getServletContext().getInitParameter("Age");
display-name tag
Yönetim ekranında gösterilen uygulama ismi.
Örnek
Şöyle yaparız. Uygulamaya http isteği ile erişmek için bu isim değil war dosyasının ismi kullanılır
<display-name>TomcatRestExample</display-name>
Örnek
Şöyle yaparız.
display-name>Spring-Hibernate</display-name>
error-page tag
Örnek
Servet 3.0'dan itibaren hata kodlarını belirtmeye gerek yok. Şöyle yaparız.
<web-app ...>
  <error-page>
    <location>/general-error.html</location>
  </error-page>
</web-app>
Örnek
Eski kodlarda şöyle yaparız.
<error-page>
  <!-- Missing login -->
  <error-code>401</error-code>
  <location>/general-error.html</location>
</error-page>
<error-page>
  <!-- Forbidden directory listing -->
  <error-code>403</error-code>
  <location>/general-error.html</location>
</error-page>
<error-page>
  <!-- Missing resource -->
  <error-code>404</error-code>
  <location>/Error404.html</location>
</error-page>
<error-page>
  <!-- Uncaught exception -->
  <error-code>500</error-code>
    <location>/general-error.html</location>
</error-page>
<error-page>
  <!-- Unsupported servlet method -->
  <error-code>503</error-code>
  <location>/general-error.html</location>
</error-page>
filter tag
Uygulamaya sadece belli IP'lerin erişmesini istersek şöyle yaparız.
<filter>
  <filter-name>Remote Address Filter</filter-name>
  <filter-class>org.apache.catalina.filters.RemoteAddrFilter</filter-class>
  <init-param>
    <param-name>allow</param-name>
    <param-value>127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>Remote Address Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
listener tag
ServletContextListener sınıfları bu tag ile tanıtılıyor.

login-config tag
login-config yazısına taşıdım

resource-ref tag
resource-ref yazısına taşıdım

security-constraint tag
security-constraint yazısına taşıdım

session-config tag
Örnek
30 dakika tanımlamak için şöyle yaparız.
<session-config>
  <session-timeout>30</session-timeout>     
  <tracking-mode>COOKIE</tracking-mode>
</session-config>
Örnek
Şöyle yaparız.
<?xml version="1.0" encoding="UTF-8"?>

<web-app ...>
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
  ...
</web-app>
servlet tag
Servlet sınıflarını tanımlıyor. <servlet-name>aa</servlet-name> verdiysek aa.xml dosyası da bu servlet'e ait olduğu için okunur

Örnek
Şöyle  yaparız:
<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
Örnek
Şöyle yaparız.
<?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"
  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">

  <display-name>TomcatRestExample</display-name>

  <servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>...</servlet-class>
    <init-param>
      <param-name>...</param-name>
      <param-value>...</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/maven/*</url-pattern>
  </servlet-mapping>

</web-app>
servlet/init-param tag
Şöyle yaparız
<servlet>
  <servlet-name>HelloWorld</servlet-name>
  <servlet-class>TestServlet</servlet-class>
  <init-param>
    <param-name>myprop</param-name>
    <param-value>value</param-value>
  </init-param>
</servlet>
Servlet içinde bur değere erişmek için şöyle yaparız.
out.println(getInitParameter("Greetings"));
servlet-mapping tag
Yukarıda tanımlanan servlet sınıfını ile servletin hizmet edeceği url adreslerini eşleştiriyor. Eşleştirme için servlete verilen ismin kullanıldığına dikkat etmek lazım.

Örnek
Şöyle yaparız.
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>/faces/*</url-pattern>
</servlet-mapping>
Servlet mapping kuralları şöyle. Bu kurallardan sadece '/' verileni ilginç.
- A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.
- A string beginning with a ‘*.’ prefix is used as an extension mapping.
- The empty string ("") is a special URL pattern that exactly maps to the application's context root, i.e., requests of the form  http://host:port/<contextroot>/. In this case the path info is ’/’ and the servlet path and context path is empty string (““).
- A string containing only the ’/’ character indicates the "default" servlet of the application. In this case the servlet path is the request URI minus the context path and the path info is null.
- All other strings are used for exact matches only
Örnek
Şöyle yaparız
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>mysite.server.HelloWorld</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>helloworld</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
Örnek
Şöyle yaparız
<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  metadata-complete="false"
  version="3.1">

  <servlet>
    <servlet-name>Hello</servlet-name>
    <servlet-class>org.example.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Hello</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>
welcome-file-list tag
Uygulama ilk açılırken gösterilecek sayfayı tanımlıyor. Şöyle yaparız:
<welcome-file-list>
  <welcome-file>index.xhtml</welcome-file>
</welcome-file-list>

Bean Validation @GroupSequence Anotasyonu

Örnek Elimizde şöyle bir kod olsun public class SampleRequest {   @NotNull   LocalDate startDate;   @NotNull   LocalDate endDate;   @AssertT...